Merge pull request #32 from fknives/issue#6-displayname
Issue#6 displayname
This commit is contained in:
commit
e34ee60df5
42 changed files with 384 additions and 175 deletions
|
|
@ -7,12 +7,12 @@ plugins {
|
|||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 31
|
||||
compileSdk 31
|
||||
|
||||
defaultConfig {
|
||||
applicationId "org.fnives.test.showcase"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 31
|
||||
minSdk 21
|
||||
targetSdk 31
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
buildConfigField "String", "BASE_URL", '"https://606844a10add49001733fe6b.mockapi.io/"'
|
||||
|
|
@ -138,7 +138,6 @@ dependencies {
|
|||
testImplementation "androidx.test.espresso:espresso-core:$testing_espresso_version"
|
||||
testImplementation "androidx.test.espresso:espresso-intents:$testing_espresso_version"
|
||||
testImplementation project(':mockserver')
|
||||
testImplementation "com.jakewharton.espresso:okhttp3-idling-resource:$testing_okhttp3_idling_resource_version"
|
||||
testImplementation "androidx.arch.core:core-testing:$testing_androidx_arch_core_version"
|
||||
testRuntimeOnly "org.junit.vintage:junit-vintage-engine:$testing_junit5_version"
|
||||
testImplementation "com.google.dagger:hilt-android-testing:$hilt_version"
|
||||
|
|
@ -153,10 +152,19 @@ dependencies {
|
|||
androidTestImplementation "androidx.test.espresso:espresso-core:$testing_espresso_version"
|
||||
androidTestImplementation "androidx.test.espresso:espresso-intents:$testing_espresso_version"
|
||||
androidTestImplementation project(':mockserver')
|
||||
androidTestImplementation "com.jakewharton.espresso:okhttp3-idling-resource:$testing_okhttp3_idling_resource_version"
|
||||
androidTestImplementation "androidx.arch.core:core-testing:$testing_androidx_arch_core_version"
|
||||
androidTestRuntimeOnly "org.junit.vintage:junit-vintage-engine:$testing_junit5_version"
|
||||
androidTestImplementation "com.google.dagger:hilt-android-testing:$hilt_version"
|
||||
kaptAndroidTest "com.google.dagger:hilt-compiler:$hilt_version"
|
||||
androidTestImplementation project(":network") // hilt needs it
|
||||
|
||||
implementation "io.reactivex.rxjava3:rxjava:3.1.2"
|
||||
}
|
||||
|
||||
|
||||
///Users/gergelyhegedus/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-jdk8/1.5.31/ff5d99aecd328872494e8921b72bf6e3af97af3e/kotlin-stdlib-jdk8-1.5.31.jar (version 1.5)
|
||||
///Users/gergelyhegedus/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-jdk7/1.5.31/77e0f2568912e45d26c31fd417a332458508acdf/kotlin-stdlib-jdk7-1.5.31.jar (version 1.5)
|
||||
///Users/gergelyhegedus/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.6.0/a40b8b22529b733892edf4b73468ce598bb17f04/kotlin-stdlib-1.6.0.jar (version 1.6)
|
||||
///Users/gergelyhegedus/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-common/1.6.0/7857e365f925cfa060f941c1357cda1f8790502c/kotlin-stdlib-common-1.6.0.jar (version 1.6)
|
||||
//w: Some runtime JAR files in the classpath have an incompatible version. Consider removing them from the classpath
|
||||
//dagger.lint.DaggerIssueRegistry in /Users/gergelyhegedus/.gradle/caches/transforms-3/7d8d9a87fed97b25e3e147795231ede4/transformed/jetified-dagger-lint-aar-2.40/jars/lint.jar does not specify a vendor; see IssueRegistry#vendor
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package org.fnives.test.showcase.ui.home
|
|||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.distinctUntilChanged
|
||||
import androidx.lifecycle.liveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
|
|
@ -52,7 +53,7 @@ class MainViewModel @Inject constructor(
|
|||
}
|
||||
val content: LiveData<List<FavouriteContent>> = _content
|
||||
private val _errorMessage = MutableLiveData<Boolean>(false)
|
||||
val errorMessage: LiveData<Boolean> = _errorMessage
|
||||
val errorMessage: LiveData<Boolean> = _errorMessage.distinctUntilChanged()
|
||||
private val _navigateToAuth = MutableLiveData<Event<Unit>>()
|
||||
val navigateToAuth: LiveData<Event<Unit>> = _navigateToAuth
|
||||
|
||||
|
|
|
|||
|
|
@ -40,8 +40,9 @@ internal class FavouriteContentLocalStorageImplTest {
|
|||
hiltRule.inject()
|
||||
}
|
||||
|
||||
/** GIVEN content_id WHEN added to Favourite THEN it can be read out */
|
||||
@Test
|
||||
fun GIVEN_content_id_WHEN_added_to_Favourite_THEN_it_can_be_read_out() = runBlocking {
|
||||
fun addingContentIdToFavouriteCanBeLaterReadOut() = runBlocking {
|
||||
val expected = listOf(ContentId("a"))
|
||||
|
||||
sut.markAsFavourite(ContentId("a"))
|
||||
|
|
@ -50,8 +51,9 @@ internal class FavouriteContentLocalStorageImplTest {
|
|||
Assert.assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
/** GIVEN content_id added WHEN removed to Favourite THEN it no longer can be read out */
|
||||
@Test
|
||||
fun GIVEN_content_id_added_WHEN_removed_to_Favourite_THEN_it_no_longer_can_be_read_out() =
|
||||
fun contentIdAddedThenRemovedCanNoLongerBeReadOut() =
|
||||
runBlocking {
|
||||
val expected = listOf<ContentId>()
|
||||
sut.markAsFavourite(ContentId("b"))
|
||||
|
|
@ -62,8 +64,9 @@ internal class FavouriteContentLocalStorageImplTest {
|
|||
Assert.assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
/** GIVEN empty database WHILE observing content WHEN favourite added THEN change is emitted */
|
||||
@Test
|
||||
fun GIVEN_empty_database_WHILE_observing_content_WHEN_favourite_added_THEN_change_is_emitted() =
|
||||
fun addingFavouriteUpdatesExistingObservers() =
|
||||
runBlocking<Unit> {
|
||||
val expected = listOf(listOf(), listOf(ContentId("a")))
|
||||
|
||||
|
|
@ -78,8 +81,9 @@ internal class FavouriteContentLocalStorageImplTest {
|
|||
Assert.assertEquals(expected, actual.await())
|
||||
}
|
||||
|
||||
/** GIVEN non empty database WHILE observing content WHEN favourite removed THEN change is emitted */
|
||||
@Test
|
||||
fun GIVEN_non_empty_database_WHILE_observing_content_WHEN_favourite_removed_THEN_change_is_emitted() =
|
||||
fun removingFavouriteUpdatesExistingObservers() =
|
||||
runBlocking<Unit> {
|
||||
val expected = listOf(listOf(ContentId("a")), listOf())
|
||||
sut.markAsFavourite(ContentId("a"))
|
||||
|
|
|
|||
|
|
@ -39,8 +39,9 @@ internal class FavouriteContentLocalStorageImplTest : KoinTest {
|
|||
stopKoin()
|
||||
}
|
||||
|
||||
/** GIVEN content_id WHEN added to Favourite THEN it can be read out */
|
||||
@Test
|
||||
fun GIVEN_content_id_WHEN_added_to_Favourite_THEN_it_can_be_read_out() = runBlocking {
|
||||
fun addingContentIdToFavouriteCanBeLaterReadOut() = runBlocking {
|
||||
val expected = listOf(ContentId("a"))
|
||||
|
||||
sut.markAsFavourite(ContentId("a"))
|
||||
|
|
@ -49,8 +50,9 @@ internal class FavouriteContentLocalStorageImplTest : KoinTest {
|
|||
Assert.assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
/** GIVEN content_id added WHEN removed to Favourite THEN it no longer can be read out */
|
||||
@Test
|
||||
fun GIVEN_content_id_added_WHEN_removed_to_Favourite_THEN_it_no_longer_can_be_read_out() =
|
||||
fun contentIdAddedThenRemovedCanNoLongerBeReadOut() =
|
||||
runBlocking {
|
||||
val expected = listOf<ContentId>()
|
||||
sut.markAsFavourite(ContentId("b"))
|
||||
|
|
@ -61,8 +63,9 @@ internal class FavouriteContentLocalStorageImplTest : KoinTest {
|
|||
Assert.assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
/** GIVEN empty database WHILE observing content WHEN favourite added THEN change is emitted */
|
||||
@Test
|
||||
fun GIVEN_empty_database_WHILE_observing_content_WHEN_favourite_added_THEN_change_is_emitted() =
|
||||
fun addingFavouriteUpdatesExistingObservers() =
|
||||
runBlocking<Unit> {
|
||||
val expected = listOf(listOf(), listOf(ContentId("a")))
|
||||
|
||||
|
|
@ -77,8 +80,9 @@ internal class FavouriteContentLocalStorageImplTest : KoinTest {
|
|||
Assert.assertEquals(expected, actual.await())
|
||||
}
|
||||
|
||||
/** GIVEN non empty database WHILE observing content WHEN favourite removed THEN change is emitted */
|
||||
@Test
|
||||
fun GIVEN_non_empty_database_WHILE_observing_content_WHEN_favourite_removed_THEN_change_is_emitted() =
|
||||
fun removingFavouriteUpdatesExistingObservers() =
|
||||
runBlocking<Unit> {
|
||||
val expected = listOf(listOf(ContentId("a")), listOf())
|
||||
sut.markAsFavourite(ContentId("a"))
|
||||
|
|
|
|||
|
|
@ -0,0 +1,46 @@
|
|||
package org.fnives.test.showcase.testutils.idling
|
||||
|
||||
import androidx.annotation.CheckResult
|
||||
import androidx.annotation.NonNull
|
||||
import androidx.test.espresso.IdlingResource
|
||||
import okhttp3.Dispatcher
|
||||
import okhttp3.OkHttpClient
|
||||
|
||||
/**
|
||||
* AndroidX version of Jake Wharton's OkHttp3IdlingResource.
|
||||
*
|
||||
* Reference: https://github.com/JakeWharton/okhttp-idling-resource/blob/master/src/main/java/com/jakewharton/espresso/OkHttp3IdlingResource.java
|
||||
*/
|
||||
class OkHttp3IdlingResource private constructor(
|
||||
private val name: String,
|
||||
private val dispatcher: Dispatcher
|
||||
) : IdlingResource {
|
||||
@Volatile
|
||||
var callback: IdlingResource.ResourceCallback? = null
|
||||
|
||||
init {
|
||||
dispatcher.idleCallback = Runnable { callback?.onTransitionToIdle() }
|
||||
}
|
||||
|
||||
override fun getName(): String = name
|
||||
|
||||
override fun isIdleNow(): Boolean = dispatcher.runningCallsCount() == 0
|
||||
|
||||
override fun registerIdleTransitionCallback(callback: IdlingResource.ResourceCallback?) {
|
||||
this.callback = callback
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Create a new [IdlingResource] from `client` as `name`. You must register
|
||||
* this instance using `Espresso.registerIdlingResources`.
|
||||
*/
|
||||
@CheckResult
|
||||
@NonNull // Extra guards as a library.
|
||||
fun create(@NonNull name: String?, @NonNull client: OkHttpClient?): OkHttp3IdlingResource {
|
||||
if (name == null) throw NullPointerException("name == null")
|
||||
if (client == null) throw NullPointerException("client == null")
|
||||
return OkHttp3IdlingResource(name, client.dispatcher)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,7 +2,6 @@ package org.fnives.test.showcase.testutils.idling
|
|||
|
||||
import androidx.annotation.CheckResult
|
||||
import androidx.test.espresso.IdlingResource
|
||||
import com.jakewharton.espresso.OkHttp3IdlingResource
|
||||
import okhttp3.OkHttpClient
|
||||
import org.fnives.test.showcase.hilt.SessionLessQualifier
|
||||
import org.fnives.test.showcase.hilt.SessionQualifier
|
||||
|
|
|
|||
|
|
@ -82,8 +82,9 @@ class MainActivityTest {
|
|||
disposable.dispose()
|
||||
}
|
||||
|
||||
/** GIVEN initialized MainActivity WHEN signout is clicked THEN user is signed out */
|
||||
@Test
|
||||
fun GIVEN_initialized_MainActivity_WHEN_signout_is_clicked_THEN_user_is_signed_out() {
|
||||
fun signOutClickedResultsInNavigation() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(ContentScenario.Error(false))
|
||||
activityScenario = ActivityScenario.launch(HiltMainActivity::class.java)
|
||||
|
|
@ -96,8 +97,9 @@ class MainActivityTest {
|
|||
Assert.assertEquals(false, setupLoggedInState.isLoggedIn())
|
||||
}
|
||||
|
||||
/** GIVEN success response WHEN data is returned THEN it is shown on the ui */
|
||||
@Test
|
||||
fun GIVEN_success_response_WHEN_data_is_returned_THEN_it_is_shown_on_the_ui() {
|
||||
fun successfulDataLoadingShowsTheElementsOnTheUI() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(ContentScenario.Success(false))
|
||||
activityScenario = ActivityScenario.launch(HiltMainActivity::class.java)
|
||||
|
|
@ -109,8 +111,9 @@ class MainActivityTest {
|
|||
homeRobot.assertDidNotNavigateToAuth()
|
||||
}
|
||||
|
||||
/** GIVEN success response WHEN item is clicked THEN ui is updated */
|
||||
@Test
|
||||
fun GIVEN_success_response_WHEN_item_is_clicked_THEN_ui_is_updated() {
|
||||
fun clickingOnListElementUpdatesTheElementsFavouriteState() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(ContentScenario.Success(false))
|
||||
activityScenario = ActivityScenario.launch(HiltMainActivity::class.java)
|
||||
|
|
@ -124,8 +127,9 @@ class MainActivityTest {
|
|||
.assertDidNotNavigateToAuth()
|
||||
}
|
||||
|
||||
/** GIVEN success response WHEN item is clicked THEN ui is updated even if activity is recreated */
|
||||
@Test
|
||||
fun GIVEN_success_response_WHEN_item_is_clicked_THEN_ui_is_updated_even_if_activity_is_recreated() {
|
||||
fun elementFavouritedIsKeptEvenIfActivityIsRecreated() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(ContentScenario.Success(false))
|
||||
activityScenario = ActivityScenario.launch(HiltMainActivity::class.java)
|
||||
|
|
@ -144,8 +148,9 @@ class MainActivityTest {
|
|||
.assertDidNotNavigateToAuth()
|
||||
}
|
||||
|
||||
/** GIVEN success response WHEN item is clicked then clicked again THEN ui is updated */
|
||||
@Test
|
||||
fun GIVEN_success_response_WHEN_item_is_clicked_then_clicked_again_THEN_ui_is_updated() {
|
||||
fun clickingAnElementMultipleTimesProperlyUpdatesIt() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(ContentScenario.Success(false))
|
||||
activityScenario = ActivityScenario.launch(HiltMainActivity::class.java)
|
||||
|
|
@ -161,8 +166,9 @@ class MainActivityTest {
|
|||
.assertDidNotNavigateToAuth()
|
||||
}
|
||||
|
||||
/** GIVEN error response WHEN loaded THEN error is Shown */
|
||||
@Test
|
||||
fun GIVEN_error_response_WHEN_loaded_THEN_error_is_Shown() {
|
||||
fun networkErrorResultsInUIErrorStateShown() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(ContentScenario.Error(false))
|
||||
activityScenario = ActivityScenario.launch(HiltMainActivity::class.java)
|
||||
|
|
@ -173,8 +179,9 @@ class MainActivityTest {
|
|||
.assertDidNotNavigateToAuth()
|
||||
}
|
||||
|
||||
/** GIVEN error response then success WHEN retried THEN success is shown */
|
||||
@Test
|
||||
fun GIVEN_error_response_then_success_WHEN_retried_THEN_success_is_shown() {
|
||||
fun retryingFromErrorStateAndSucceedingShowsTheData() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(
|
||||
ContentScenario.Error(false)
|
||||
|
|
@ -193,8 +200,9 @@ class MainActivityTest {
|
|||
homeRobot.assertDidNotNavigateToAuth()
|
||||
}
|
||||
|
||||
/** GIVEN success then error WHEN retried THEN error is shown */
|
||||
@Test
|
||||
fun GIVEN_success_then_error_WHEN_retried_THEN_error_is_shown() {
|
||||
fun errorIsShownIfTheDataIsFetchedAndErrorIsReceived() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(
|
||||
ContentScenario.Success(false)
|
||||
|
|
@ -215,8 +223,9 @@ class MainActivityTest {
|
|||
.assertDidNotNavigateToAuth()
|
||||
}
|
||||
|
||||
/** GIVEN unauthenticated then success WHEN loaded THEN success is shown */
|
||||
@Test
|
||||
fun GIVEN_unauthenticated_then_success_WHEN_loaded_THEN_success_is_shown() {
|
||||
fun authenticationIsHandledWithASingleLoading() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(
|
||||
ContentScenario.Unauthorized(false)
|
||||
|
|
@ -233,8 +242,9 @@ class MainActivityTest {
|
|||
homeRobot.assertDidNotNavigateToAuth()
|
||||
}
|
||||
|
||||
/** GIVEN unauthenticated then error WHEN loaded THEN navigated to auth */
|
||||
@Test
|
||||
fun GIVEN_unauthenticated_then_error_WHEN_loaded_THEN_navigated_to_auth() {
|
||||
fun sessionExpirationResultsInNavigation() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(ContentScenario.Unauthorized(false))
|
||||
.setScenario(RefreshTokenScenario.Error)
|
||||
|
|
|
|||
|
|
@ -72,8 +72,9 @@ class AuthActivityTest {
|
|||
disposable.dispose()
|
||||
}
|
||||
|
||||
/** GIVEN non empty password and username and successful response WHEN signIn THEN no error is shown and navigating to home */
|
||||
@Test
|
||||
fun GIVEN_non_empty_password_and_username_and_successful_response_WHEN_signIn_THEN_no_error_is_shown_and_navigating_to_home() {
|
||||
fun properLoginResultsInNavigationToHome() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup.setScenario(
|
||||
AuthScenario.Success(
|
||||
password = "alma",
|
||||
|
|
@ -93,8 +94,9 @@ class AuthActivityTest {
|
|||
loginRobot.assertNavigatedToHome()
|
||||
}
|
||||
|
||||
/** GIVEN empty password and username WHEN signIn THEN error password is shown */
|
||||
@Test
|
||||
fun GIVEN_empty_password_and_username_WHEN_signIn_THEN_error_password_is_shown() {
|
||||
fun emptyPasswordShowsProperErrorMessage() {
|
||||
activityScenario = ActivityScenario.launch(HiltAuthActivity::class.java)
|
||||
loginRobot
|
||||
.setUsername("banan")
|
||||
|
|
@ -108,8 +110,9 @@ class AuthActivityTest {
|
|||
.assertNotLoading()
|
||||
}
|
||||
|
||||
/** GIVEN password and empty username WHEN signIn THEN error username is shown */
|
||||
@Test
|
||||
fun GIVEN_password_and_empty_username_WHEN_signIn_THEN_error_username_is_shown() {
|
||||
fun emptyUserNameShowsProperErrorMessage() {
|
||||
activityScenario = ActivityScenario.launch(HiltAuthActivity::class.java)
|
||||
loginRobot
|
||||
.setPassword("banan")
|
||||
|
|
@ -123,8 +126,9 @@ class AuthActivityTest {
|
|||
.assertNotLoading()
|
||||
}
|
||||
|
||||
/** GIVEN password and username and invalid credentials response WHEN signIn THEN error invalid credentials is shown */
|
||||
@Test
|
||||
fun GIVEN_password_and_username_and_invalid_credentials_response_WHEN_signIn_THEN_error_invalid_credentials_is_shown() {
|
||||
fun invalidCredentialsGivenShowsProperErrorMessage() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup.setScenario(
|
||||
AuthScenario.InvalidCredentials(username = "alma", password = "banan")
|
||||
)
|
||||
|
|
@ -143,8 +147,9 @@ class AuthActivityTest {
|
|||
.assertNotLoading()
|
||||
}
|
||||
|
||||
/** GIVEN password and username and error response WHEN signIn THEN error invalid credentials is shown */
|
||||
@Test
|
||||
fun GIVEN_password_and_username_and_error_response_WHEN_signIn_THEN_error_invalid_credentials_is_shown() {
|
||||
fun networkErrorShowsProperErrorMessage() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup.setScenario(
|
||||
AuthScenario.GenericError(username = "alma", password = "banan")
|
||||
)
|
||||
|
|
|
|||
|
|
@ -71,8 +71,9 @@ class SplashActivityTest : KoinTest {
|
|||
disposable?.dispose()
|
||||
}
|
||||
|
||||
/** GIVEN loggedInState WHEN opened THEN MainActivity is started */
|
||||
@Test
|
||||
fun GIVEN_loggedInState_WHEN_opened_THEN_MainActivity_is_started() {
|
||||
fun loggedInStateNavigatesToHome() {
|
||||
setupLoggedInState.setupLogin(mockServerScenarioSetupTestRule.mockServerScenarioSetup)
|
||||
|
||||
activityScenario = ActivityScenario.launch(HiltSplashActivity::class.java)
|
||||
|
|
@ -85,8 +86,9 @@ class SplashActivityTest : KoinTest {
|
|||
setupLoggedInState.setupLogout()
|
||||
}
|
||||
|
||||
/** GIVEN loggedOffState WHEN opened THEN AuthActivity is started */
|
||||
@Test
|
||||
fun GIVEN_loggedOffState_WHEN_opened_THEN_AuthActivity_is_started() {
|
||||
fun loggedOutStatesNavigatesToAuthentication() {
|
||||
setupLoggedInState.setupLogout()
|
||||
|
||||
activityScenario = ActivityScenario.launch(HiltSplashActivity::class.java)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package org.fnives.test.showcase.testutils.idling
|
|||
|
||||
import androidx.annotation.CheckResult
|
||||
import androidx.test.espresso.IdlingResource
|
||||
import com.jakewharton.espresso.OkHttp3IdlingResource
|
||||
import okhttp3.OkHttpClient
|
||||
import org.koin.core.qualifier.StringQualifier
|
||||
import org.koin.test.KoinTest
|
||||
|
|
|
|||
|
|
@ -37,7 +37,8 @@ class MainActivityTest : KoinTest {
|
|||
|
||||
@Rule
|
||||
@JvmField
|
||||
val snackbarVerificationTestRule = SpecificTestConfigurationsFactory.createSnackbarVerification()
|
||||
val snackbarVerificationTestRule =
|
||||
SpecificTestConfigurationsFactory.createSnackbarVerification()
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
|
|
@ -73,8 +74,9 @@ class MainActivityTest : KoinTest {
|
|||
disposable.dispose()
|
||||
}
|
||||
|
||||
/** GIVEN initialized MainActivity WHEN signout is clicked THEN user is signed out */
|
||||
@Test
|
||||
fun GIVEN_initialized_MainActivity_WHEN_signout_is_clicked_THEN_user_is_signed_out() {
|
||||
fun signOutClickedResultsInNavigation() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(ContentScenario.Error(false))
|
||||
activityScenario = ActivityScenario.launch(MainActivity::class.java)
|
||||
|
|
@ -87,8 +89,9 @@ class MainActivityTest : KoinTest {
|
|||
Assert.assertEquals(false, SetupLoggedInState.isLoggedIn())
|
||||
}
|
||||
|
||||
/** GIVEN success response WHEN data is returned THEN it is shown on the ui */
|
||||
@Test
|
||||
fun GIVEN_success_response_WHEN_data_is_returned_THEN_it_is_shown_on_the_ui() {
|
||||
fun successfulDataLoadingShowsTheElementsOnTheUI() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(ContentScenario.Success(false))
|
||||
activityScenario = ActivityScenario.launch(MainActivity::class.java)
|
||||
|
|
@ -100,8 +103,9 @@ class MainActivityTest : KoinTest {
|
|||
homeRobot.assertDidNotNavigateToAuth()
|
||||
}
|
||||
|
||||
/** GIVEN success response WHEN item is clicked THEN ui is updated */
|
||||
@Test
|
||||
fun GIVEN_success_response_WHEN_item_is_clicked_THEN_ui_is_updated() {
|
||||
fun clickingOnListElementUpdatesTheElementsFavouriteState() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(ContentScenario.Success(false))
|
||||
activityScenario = ActivityScenario.launch(MainActivity::class.java)
|
||||
|
|
@ -115,8 +119,9 @@ class MainActivityTest : KoinTest {
|
|||
.assertDidNotNavigateToAuth()
|
||||
}
|
||||
|
||||
/** GIVEN success response WHEN item is clicked THEN ui is updated even if activity is recreated */
|
||||
@Test
|
||||
fun GIVEN_success_response_WHEN_item_is_clicked_THEN_ui_is_updated_even_if_activity_is_recreated() {
|
||||
fun elementFavouritedIsKeptEvenIfActivityIsRecreated() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(ContentScenario.Success(false))
|
||||
activityScenario = ActivityScenario.launch(MainActivity::class.java)
|
||||
|
|
@ -135,8 +140,9 @@ class MainActivityTest : KoinTest {
|
|||
.assertDidNotNavigateToAuth()
|
||||
}
|
||||
|
||||
/** GIVEN success response WHEN item is clicked then clicked again THEN ui is updated */
|
||||
@Test
|
||||
fun GIVEN_success_response_WHEN_item_is_clicked_then_clicked_again_THEN_ui_is_updated() {
|
||||
fun clickingAnElementMultipleTimesProperlyUpdatesIt() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(ContentScenario.Success(false))
|
||||
activityScenario = ActivityScenario.launch(MainActivity::class.java)
|
||||
|
|
@ -152,8 +158,9 @@ class MainActivityTest : KoinTest {
|
|||
.assertDidNotNavigateToAuth()
|
||||
}
|
||||
|
||||
/** GIVEN error response WHEN loaded THEN error is Shown */
|
||||
@Test
|
||||
fun GIVEN_error_response_WHEN_loaded_THEN_error_is_Shown() {
|
||||
fun networkErrorResultsInUIErrorStateShown() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(ContentScenario.Error(false))
|
||||
activityScenario = ActivityScenario.launch(MainActivity::class.java)
|
||||
|
|
@ -164,8 +171,9 @@ class MainActivityTest : KoinTest {
|
|||
.assertDidNotNavigateToAuth()
|
||||
}
|
||||
|
||||
/** GIVEN error response then success WHEN retried THEN success is shown */
|
||||
@Test
|
||||
fun GIVEN_error_response_then_success_WHEN_retried_THEN_success_is_shown() {
|
||||
fun retryingFromErrorStateAndSucceedingShowsTheData() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(
|
||||
ContentScenario.Error(false)
|
||||
|
|
@ -184,8 +192,9 @@ class MainActivityTest : KoinTest {
|
|||
homeRobot.assertDidNotNavigateToAuth()
|
||||
}
|
||||
|
||||
/** GIVEN success then error WHEN retried THEN error is shown */
|
||||
@Test
|
||||
fun GIVEN_success_then_error_WHEN_retried_THEN_error_is_shown() {
|
||||
fun errorIsShownIfTheDataIsFetchedAndErrorIsReceived() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(
|
||||
ContentScenario.Success(false)
|
||||
|
|
@ -206,8 +215,9 @@ class MainActivityTest : KoinTest {
|
|||
.assertDidNotNavigateToAuth()
|
||||
}
|
||||
|
||||
/** GIVEN unauthenticated then success WHEN loaded THEN success is shown */
|
||||
@Test
|
||||
fun GIVEN_unauthenticated_then_success_WHEN_loaded_THEN_success_is_shown() {
|
||||
fun authenticationIsHandledWithASingleLoading() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(
|
||||
ContentScenario.Unauthorized(false)
|
||||
|
|
@ -224,8 +234,9 @@ class MainActivityTest : KoinTest {
|
|||
homeRobot.assertDidNotNavigateToAuth()
|
||||
}
|
||||
|
||||
/** GIVEN unauthenticated then error WHEN loaded THEN navigated to auth */
|
||||
@Test
|
||||
fun GIVEN_unauthenticated_then_error_WHEN_loaded_THEN_navigated_to_auth() {
|
||||
fun sessionExpirationResultsInNavigation() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(ContentScenario.Unauthorized(false))
|
||||
.setScenario(RefreshTokenScenario.Error)
|
||||
|
|
|
|||
|
|
@ -66,8 +66,9 @@ class AuthActivityTest : KoinTest {
|
|||
disposable.dispose()
|
||||
}
|
||||
|
||||
/** GIVEN non empty password and username and successful response WHEN signIn THEN no error is shown and navigating to home */
|
||||
@Test
|
||||
fun GIVEN_non_empty_password_and_username_and_successful_response_WHEN_signIn_THEN_no_error_is_shown_and_navigating_to_home() {
|
||||
fun properLoginResultsInNavigationToHome() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup.setScenario(
|
||||
AuthScenario.Success(
|
||||
password = "alma",
|
||||
|
|
@ -87,8 +88,9 @@ class AuthActivityTest : KoinTest {
|
|||
loginRobot.assertNavigatedToHome()
|
||||
}
|
||||
|
||||
/** GIVEN empty password and username WHEN signIn THEN error password is shown */
|
||||
@Test
|
||||
fun GIVEN_empty_password_and_username_WHEN_signIn_THEN_error_password_is_shown() {
|
||||
fun emptyPasswordShowsProperErrorMessage() {
|
||||
activityScenario = ActivityScenario.launch(AuthActivity::class.java)
|
||||
loginRobot
|
||||
.setUsername("banan")
|
||||
|
|
@ -102,8 +104,9 @@ class AuthActivityTest : KoinTest {
|
|||
.assertNotLoading()
|
||||
}
|
||||
|
||||
/** GIVEN password and empty username WHEN signIn THEN error username is shown */
|
||||
@Test
|
||||
fun GIVEN_password_and_empty_username_WHEN_signIn_THEN_error_username_is_shown() {
|
||||
fun emptyUserNameShowsProperErrorMessage() {
|
||||
activityScenario = ActivityScenario.launch(AuthActivity::class.java)
|
||||
loginRobot
|
||||
.setPassword("banan")
|
||||
|
|
@ -117,8 +120,9 @@ class AuthActivityTest : KoinTest {
|
|||
.assertNotLoading()
|
||||
}
|
||||
|
||||
/** GIVEN password and username and invalid credentials response WHEN signIn THEN error invalid credentials is shown */
|
||||
@Test
|
||||
fun GIVEN_password_and_username_and_invalid_credentials_response_WHEN_signIn_THEN_error_invalid_credentials_is_shown() {
|
||||
fun invalidCredentialsGivenShowsProperErrorMessage() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup.setScenario(
|
||||
AuthScenario.InvalidCredentials(username = "alma", password = "banan")
|
||||
)
|
||||
|
|
@ -137,8 +141,9 @@ class AuthActivityTest : KoinTest {
|
|||
.assertNotLoading()
|
||||
}
|
||||
|
||||
/** GIVEN password and username and error response WHEN signIn THEN error invalid credentials is shown */
|
||||
@Test
|
||||
fun GIVEN_password_and_username_and_error_response_WHEN_signIn_THEN_error_invalid_credentials_is_shown() {
|
||||
fun networkErrorShowsProperErrorMessage() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup.setScenario(
|
||||
AuthScenario.GenericError(username = "alma", password = "banan")
|
||||
)
|
||||
|
|
|
|||
|
|
@ -61,8 +61,9 @@ class SplashActivityTest : KoinTest {
|
|||
disposable.dispose()
|
||||
}
|
||||
|
||||
/** GIVEN loggedInState WHEN opened THEN MainActivity is started */
|
||||
@Test
|
||||
fun GIVEN_loggedInState_WHEN_opened_THEN_MainActivity_is_started() {
|
||||
fun loggedInStateNavigatesToHome() {
|
||||
SetupLoggedInState.setupLogin(mockServerScenarioSetupTestRule.mockServerScenarioSetup)
|
||||
|
||||
activityScenario = ActivityScenario.launch(SplashActivity::class.java)
|
||||
|
|
@ -75,8 +76,9 @@ class SplashActivityTest : KoinTest {
|
|||
SetupLoggedInState.setupLogout()
|
||||
}
|
||||
|
||||
/** GIVEN loggedOffState WHEN opened THEN AuthActivity is started */
|
||||
@Test
|
||||
fun GIVEN_loggedOffState_WHEN_opened_THEN_AuthActivity_is_started() {
|
||||
fun loggedOutStatesNavigatesToAuthentication() {
|
||||
SetupLoggedInState.setupLogout()
|
||||
|
||||
activityScenario = ActivityScenario.launch(SplashActivity::class.java)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,14 @@ import org.junit.jupiter.api.extension.AfterEachCallback
|
|||
import org.junit.jupiter.api.extension.BeforeEachCallback
|
||||
import org.junit.jupiter.api.extension.ExtensionContext
|
||||
|
||||
/**
|
||||
* Junit5 Version of InstantTaskExecutorRule from Junit4
|
||||
*
|
||||
* reference: https://developer.android.com/reference/androidx/arch/core/executor/testing/InstantTaskExecutorRule
|
||||
*
|
||||
* A JUnit5 Extensions that swaps the background executor used by the Architecture Components with a different one which executes each task synchronously.
|
||||
* You can use this extension for your host side tests that use Architecture Components.
|
||||
*/
|
||||
class InstantExecutorExtension : BeforeEachCallback, AfterEachCallback {
|
||||
|
||||
override fun beforeEach(context: ExtensionContext?) {
|
||||
|
|
|
|||
|
|
@ -5,10 +5,16 @@ import kotlinx.coroutines.test.TestCoroutineDispatcher
|
|||
import kotlinx.coroutines.test.resetMain
|
||||
import kotlinx.coroutines.test.setMain
|
||||
import org.fnives.test.showcase.storage.database.DatabaseInitialization
|
||||
import org.fnives.test.showcase.testutils.TestMainDispatcher.Companion.testDispatcher
|
||||
import org.junit.jupiter.api.extension.AfterEachCallback
|
||||
import org.junit.jupiter.api.extension.BeforeEachCallback
|
||||
import org.junit.jupiter.api.extension.ExtensionContext
|
||||
|
||||
/**
|
||||
* Custom Junit5 Extension which replaces the [DatabaseInitialization]'s dispatcher and main dispatcher with a [TestCoroutineDispatcher]
|
||||
*
|
||||
* One can access the test dispatcher via [testDispatcher] static getter.
|
||||
*/
|
||||
class TestMainDispatcher : BeforeEachCallback, AfterEachCallback {
|
||||
|
||||
override fun beforeEach(context: ExtensionContext?) {
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ internal class AuthViewModelTest {
|
|||
sut = AuthViewModel(mockLoginUseCase)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN_initialized_viewModel_WHEN_observed_THEN_loading_false_other_fields_are_empty")
|
||||
@DisplayName("GIVEN initialized viewModel WHEN observed THEN loading false other fields are empty")
|
||||
@Test
|
||||
fun initialSetup() {
|
||||
testDispatcher.resumeDispatcher()
|
||||
|
|
@ -51,7 +51,7 @@ internal class AuthViewModelTest {
|
|||
sut.navigateToHome.test().assertNoValue()
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN_password_text_WHEN_onPasswordChanged_is_called_THEN_password_livedata_is_updated")
|
||||
@DisplayName("GIVEN password text WHEN onPasswordChanged is called THEN password livedata is updated")
|
||||
@Test
|
||||
fun whenPasswordChangedLiveDataIsUpdated() {
|
||||
testDispatcher.resumeDispatcher()
|
||||
|
|
@ -67,7 +67,7 @@ internal class AuthViewModelTest {
|
|||
sut.navigateToHome.test().assertNoValue()
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN_username_text_WHEN_onUsernameChanged_is_called_THEN_username_livedata_is_updated")
|
||||
@DisplayName("GIVEN username text WHEN onUsernameChanged is called THEN username livedata is updated")
|
||||
@Test
|
||||
fun whenUsernameChangedLiveDataIsUpdated() {
|
||||
testDispatcher.resumeDispatcher()
|
||||
|
|
@ -83,7 +83,7 @@ internal class AuthViewModelTest {
|
|||
sut.navigateToHome.test().assertNoValue()
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN_no_password_or_username_WHEN_login_is_Called_THEN_empty_credentials_are_used_in_usecase")
|
||||
@DisplayName("GIVEN no password or username WHEN login is Called THEN empty credentials are used in usecase")
|
||||
@Test
|
||||
fun noPasswordUsesEmptyStringInLoginUseCase() {
|
||||
val loadingTestObserver = sut.loading.test()
|
||||
|
|
@ -99,8 +99,9 @@ internal class AuthViewModelTest {
|
|||
verifyNoMoreInteractions(mockLoginUseCase)
|
||||
}
|
||||
|
||||
@DisplayName("WHEN login is called twice before finishing THEN use case is only called once")
|
||||
@Test
|
||||
fun WHEN_login_is_Called_twice_THEN_use_case_is_only_called_once() {
|
||||
fun onlyOneLoginIsSentOutWhenClickingRepeatedly() {
|
||||
runBlocking { whenever(mockLoginUseCase.invoke(anyOrNull())).doReturn(Answer.Error(Throwable())) }
|
||||
|
||||
sut.onLogin()
|
||||
|
|
@ -111,8 +112,9 @@ internal class AuthViewModelTest {
|
|||
verifyNoMoreInteractions(mockLoginUseCase)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN password and username WHEN login is called THEN proper credentials are used in usecase")
|
||||
@Test
|
||||
fun GIVEN_password_and_username_WHEN_login_is_Called_THEN_not_empty_credentials_are_used_in_usecase() {
|
||||
fun argumentsArePassedProperlyToLoginUseCase() {
|
||||
runBlocking {
|
||||
whenever(mockLoginUseCase.invoke(anyOrNull())).doReturn(Answer.Error(Throwable()))
|
||||
}
|
||||
|
|
@ -128,8 +130,9 @@ internal class AuthViewModelTest {
|
|||
verifyNoMoreInteractions(mockLoginUseCase)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN AnswerError WHEN login called THEN error is shown")
|
||||
@Test
|
||||
fun GIVEN_answer_error_WHEN_login_called_THEN_error_is_shown() {
|
||||
fun loginErrorResultsInErrorState() {
|
||||
runBlocking {
|
||||
whenever(mockLoginUseCase.invoke(anyOrNull())).doReturn(Answer.Error(Throwable()))
|
||||
}
|
||||
|
|
@ -146,8 +149,8 @@ internal class AuthViewModelTest {
|
|||
}
|
||||
|
||||
@MethodSource("loginErrorStatusesArguments")
|
||||
@ParameterizedTest(name = "GIVEN_answer_success_loginStatus_{0}_WHEN_login_called_THEN_error_{1}_is_shown")
|
||||
fun GIVEN_answer_success_invalid_loginStatus_WHEN_login_called_THEN_error_is_shown(
|
||||
@ParameterizedTest(name = "GIVEN answer success loginStatus {0} WHEN login called THEN error {1} is shown")
|
||||
fun invalidStatusResultsInErrorState(
|
||||
loginStatus: LoginStatus,
|
||||
errorType: AuthViewModel.ErrorType
|
||||
) {
|
||||
|
|
@ -166,8 +169,9 @@ internal class AuthViewModelTest {
|
|||
navigateToHomeObserver.assertNoValue()
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN answer success and login status success WHEN login called THEN navigation event is sent")
|
||||
@Test
|
||||
fun GIVEN_answer_success_login_status_success_WHEN_login_called_THEN_navigation_event_is_sent() {
|
||||
fun successLoginResultsInNavigation() {
|
||||
runBlocking {
|
||||
whenever(mockLoginUseCase.invoke(anyOrNull())).doReturn(Answer.Success(LoginStatus.SUCCESS))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,22 +24,22 @@ class CodeKataAuthViewModel {
|
|||
sut = AuthViewModel(mockLoginUseCase)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN_initialized_viewModel_WHEN_observed_THEN_loading_false_other_fields_are_empty")
|
||||
@DisplayName("GIVEN initialized viewModel WHEN observed THEN loading false other fields are empty")
|
||||
@Test
|
||||
fun initialSetup() {
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN_password_text_WHEN_onPasswordChanged_is_called_THEN_password_livedata_is_updated")
|
||||
@DisplayName("GIVEN password text WHEN onPasswordChanged is called THEN password livedata is updated")
|
||||
@Test
|
||||
fun whenPasswordChangedLiveDataIsUpdated() {
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN_username_text_WHEN_onUsernameChanged_is_called_THEN_username_livedata_is_updated")
|
||||
@DisplayName("GIVEN username text WHEN onUsernameChanged is called THEN username livedata is updated")
|
||||
@Test
|
||||
fun whenUsernameChangedLiveDataIsUpdated() {
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN_no_password_or_username_WHEN_login_is_Called_THEN_empty_credentials_are_used_in_usecase")
|
||||
@DisplayName("GIVEN no password or username WHEN login is Called THEN empty credentials are used in usecase")
|
||||
@Test
|
||||
fun noPasswordUsesEmptyStringInLoginUseCase() {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import org.fnives.test.showcase.model.shared.Resource
|
|||
import org.fnives.test.showcase.testutils.InstantExecutorExtension
|
||||
import org.fnives.test.showcase.testutils.TestMainDispatcher
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.mockito.kotlin.doReturn
|
||||
|
|
@ -55,16 +56,18 @@ internal class MainViewModelTest {
|
|||
)
|
||||
}
|
||||
|
||||
@DisplayName("WHEN initialization THEN error false other states empty")
|
||||
@Test
|
||||
fun WHEN_initialization_THEN_error_false_other_states_empty() {
|
||||
fun initialStateIsCorrect() {
|
||||
sut.errorMessage.test().assertValue(false)
|
||||
sut.content.test().assertNoValue()
|
||||
sut.loading.test().assertNoValue()
|
||||
sut.navigateToAuth.test().assertNoValue()
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN initialized viewModel WHEN loading is returned THEN loading is shown")
|
||||
@Test
|
||||
fun GIVEN_initialized_viewModel_WHEN_loading_is_returned_THEN_loading_is_shown() {
|
||||
fun loadingDataShowsInLoadingUIState() {
|
||||
whenever(mockGetAllContentUseCase.get()).doReturn(flowOf(Resource.Loading()))
|
||||
testDispatcher.resumeDispatcher()
|
||||
testDispatcher.advanceUntilIdle()
|
||||
|
|
@ -75,8 +78,9 @@ internal class MainViewModelTest {
|
|||
sut.navigateToAuth.test().assertNoValue()
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN loading then data WHEN observing content THEN proper states are shown")
|
||||
@Test
|
||||
fun GIVEN_loading_then_data_WHEN_observing_content_THEN_proper_states_are_shown() {
|
||||
fun loadingThenLoadedDataResultsInProperUIStates() {
|
||||
whenever(mockGetAllContentUseCase.get()).doReturn(flowOf(Resource.Loading(), Resource.Success(emptyList())))
|
||||
val errorMessageTestObserver = sut.errorMessage.test()
|
||||
val contentTestObserver = sut.content.test()
|
||||
|
|
@ -84,14 +88,15 @@ internal class MainViewModelTest {
|
|||
testDispatcher.resumeDispatcher()
|
||||
testDispatcher.advanceUntilIdle()
|
||||
|
||||
errorMessageTestObserver.assertValueHistory(false, false, false)
|
||||
errorMessageTestObserver.assertValueHistory(false)
|
||||
contentTestObserver.assertValueHistory(listOf())
|
||||
loadingTestObserver.assertValueHistory(true, false)
|
||||
sut.navigateToAuth.test().assertNoValue()
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN loading then error WHEN observing content THEN proper states are shown")
|
||||
@Test
|
||||
fun GIVEN_loading_then_error_WHEN_observing_content_THEN_proper_states_are_shown() {
|
||||
fun loadingThenErrorResultsInProperUIStates() {
|
||||
whenever(mockGetAllContentUseCase.get()).doReturn(flowOf(Resource.Loading(), Resource.Error(Throwable())))
|
||||
val errorMessageTestObserver = sut.errorMessage.test()
|
||||
val contentTestObserver = sut.content.test()
|
||||
|
|
@ -99,14 +104,15 @@ internal class MainViewModelTest {
|
|||
testDispatcher.resumeDispatcher()
|
||||
testDispatcher.advanceUntilIdle()
|
||||
|
||||
errorMessageTestObserver.assertValueHistory(false, false, true)
|
||||
errorMessageTestObserver.assertValueHistory(false, true)
|
||||
contentTestObserver.assertValueHistory(emptyList())
|
||||
loadingTestObserver.assertValueHistory(true, false)
|
||||
sut.navigateToAuth.test().assertNoValue()
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN loading then error then loading then data WHEN observing content THEN proper states are shown")
|
||||
@Test
|
||||
fun GIVEN_loading_then_error_then_loading_then_data_WHEN_observing_content_THEN_proper_states_are_shown() {
|
||||
fun loadingThenErrorThenLoadingThenDataResultsInProperUIStates() {
|
||||
val content = listOf(
|
||||
FavouriteContent(Content(ContentId(""), "", "", ImageUrl("")), false)
|
||||
)
|
||||
|
|
@ -124,14 +130,15 @@ internal class MainViewModelTest {
|
|||
testDispatcher.resumeDispatcher()
|
||||
testDispatcher.advanceUntilIdle()
|
||||
|
||||
errorMessageTestObserver.assertValueHistory(false, false, true, false, false)
|
||||
errorMessageTestObserver.assertValueHistory(false, true, false)
|
||||
contentTestObserver.assertValueHistory(emptyList(), content)
|
||||
loadingTestObserver.assertValueHistory(true, false, true, false)
|
||||
sut.navigateToAuth.test().assertNoValue()
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN loading viewModel WHEN refreshing THEN usecase is not called")
|
||||
@Test
|
||||
fun GIVEN_loading_viewModel_WHEN_refreshing_THEN_usecase_is_not_called() {
|
||||
fun fetchIsIgnoredIfViewModelIsStillLoading() {
|
||||
whenever(mockGetAllContentUseCase.get()).doReturn(flowOf(Resource.Loading()))
|
||||
sut.content.test()
|
||||
testDispatcher.resumeDispatcher()
|
||||
|
|
@ -143,8 +150,9 @@ internal class MainViewModelTest {
|
|||
verifyZeroInteractions(mockFetchContentUseCase)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN non loading viewModel WHEN refreshing THEN usecase is called")
|
||||
@Test
|
||||
fun GIVEN_non_loading_viewModel_WHEN_refreshing_THEN_usecase_is_called() {
|
||||
fun fetchIsCalledIfViewModelIsLoaded() {
|
||||
whenever(mockGetAllContentUseCase.get()).doReturn(flowOf())
|
||||
sut.content.test()
|
||||
testDispatcher.resumeDispatcher()
|
||||
|
|
@ -157,8 +165,9 @@ internal class MainViewModelTest {
|
|||
verifyNoMoreInteractions(mockFetchContentUseCase)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN loading viewModel WHEN loging out THEN usecase is called")
|
||||
@Test
|
||||
fun GIVEN_loading_viewModel_WHEN_loging_out_THEN_usecase_is_called() {
|
||||
fun loadingViewModelStillCalsLogout() {
|
||||
whenever(mockGetAllContentUseCase.get()).doReturn(flowOf(Resource.Loading()))
|
||||
sut.content.test()
|
||||
testDispatcher.resumeDispatcher()
|
||||
|
|
@ -171,8 +180,9 @@ internal class MainViewModelTest {
|
|||
verifyNoMoreInteractions(mockLogoutUseCase)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN non loading viewModel WHEN loging out THEN usecase is called")
|
||||
@Test
|
||||
fun GIVEN_non_loading_viewModel_WHEN_loging_out_THEN_usecase_is_called() {
|
||||
fun nonLoadingViewModelStillCalsLogout() {
|
||||
whenever(mockGetAllContentUseCase.get()).doReturn(flowOf())
|
||||
sut.content.test()
|
||||
testDispatcher.resumeDispatcher()
|
||||
|
|
@ -185,8 +195,9 @@ internal class MainViewModelTest {
|
|||
verifyNoMoreInteractions(mockLogoutUseCase)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN success content list viewModel WHEN toggling a nonexistent contentId THEN nothing happens")
|
||||
@Test
|
||||
fun GIVEN_success_content_list_viewModel_WHEN_toggling_a_nonexistent_contentId_THEN_nothing_happens() {
|
||||
fun interactionWithNonExistentContentIdIsIgnored() {
|
||||
val contents = listOf(
|
||||
FavouriteContent(Content(ContentId("a"), "", "", ImageUrl("")), false),
|
||||
FavouriteContent(Content(ContentId("b"), "", "", ImageUrl("")), true)
|
||||
|
|
@ -203,8 +214,9 @@ internal class MainViewModelTest {
|
|||
verifyZeroInteractions(mockAddContentToFavouriteUseCase)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN success content list viewModel WHEN toggling a favourite contentId THEN remove favourite usecase is called")
|
||||
@Test
|
||||
fun GIVEN_success_content_list_viewModel_WHEN_toggling_a_favourite_contentId_THEN_remove_favourite_usecase_is_called() {
|
||||
fun togglingFavouriteContentCallsRemoveFromFavourite() {
|
||||
val contents = listOf(
|
||||
FavouriteContent(Content(ContentId("a"), "", "", ImageUrl("")), false),
|
||||
FavouriteContent(Content(ContentId("b"), "", "", ImageUrl("")), true)
|
||||
|
|
@ -222,8 +234,9 @@ internal class MainViewModelTest {
|
|||
verifyZeroInteractions(mockAddContentToFavouriteUseCase)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN success content list viewModel WHEN toggling a not favourite contentId THEN add favourite usecase is called")
|
||||
@Test
|
||||
fun GIVEN_success_content_list_viewModel_WHEN_toggling_a_not_favourite_contentId_THEN_add_favourite_usecase_is_called() {
|
||||
fun togglingNonFavouriteContentCallsAddToFavourite() {
|
||||
val contents = listOf(
|
||||
FavouriteContent(Content(ContentId("a"), "", "", ImageUrl("")), false),
|
||||
FavouriteContent(Content(ContentId("b"), "", "", ImageUrl("")), true)
|
||||
|
|
|
|||
|
|
@ -1,13 +1,15 @@
|
|||
package org.fnives.test.showcase.ui.shared
|
||||
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
@Suppress("TestFunctionName")
|
||||
internal class EventTest {
|
||||
|
||||
@DisplayName("GIVEN event WHEN consumed is called THEN value is returned")
|
||||
@Test
|
||||
fun GIVEN_event_WHEN_consumed_is_called_THEN_value_is_returned() {
|
||||
fun consumedReturnsValue() {
|
||||
val expected = "a"
|
||||
|
||||
val actual = Event("a").consume()
|
||||
|
|
@ -15,8 +17,9 @@ internal class EventTest {
|
|||
Assertions.assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN consumed event WHEN consumed is called THEN null is returned")
|
||||
@Test
|
||||
fun GIVEN_consumed_event_WHEN_consumed_is_called_THEN_null_is_returned() {
|
||||
fun consumedEventReturnsNull() {
|
||||
val expected: String? = null
|
||||
val event = Event("a")
|
||||
event.consume()
|
||||
|
|
@ -26,8 +29,9 @@ internal class EventTest {
|
|||
Assertions.assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN event WHEN peek is called THEN value is returned")
|
||||
@Test
|
||||
fun GIVEN_event_WHEN_peek_is_called_THEN_value_is_returned() {
|
||||
fun peekReturnsValue() {
|
||||
val expected = "a"
|
||||
|
||||
val actual = Event("a").peek()
|
||||
|
|
@ -35,8 +39,9 @@ internal class EventTest {
|
|||
Assertions.assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN consumed event WHEN peek is called THEN value is returned")
|
||||
@Test
|
||||
fun GIVEN_consumed_event_WHEN_peek_is_called_THEN_value_is_returned() {
|
||||
fun consumedEventPeekedReturnsValue() {
|
||||
val expected = "a"
|
||||
val event = Event("a")
|
||||
event.consume()
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ buildscript {
|
|||
}
|
||||
dependencies {
|
||||
classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
|
||||
classpath 'com.android.tools.build:gradle:7.0.3'
|
||||
classpath 'com.android.tools.build:gradle:7.0.4'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
classpath "org.jlleitschuh.gradle:ktlint-gradle:10.2.0"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import org.fnives.test.showcase.core.storage.content.FavouriteContentLocalStorag
|
|||
import org.fnives.test.showcase.model.content.ContentId
|
||||
import org.junit.jupiter.api.Assertions.assertThrows
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.kotlin.doThrow
|
||||
import org.mockito.kotlin.mock
|
||||
|
|
@ -27,22 +28,27 @@ internal class AddContentToFavouriteUseCaseTest {
|
|||
sut = AddContentToFavouriteUseCase(mockFavouriteContentLocalStorage)
|
||||
}
|
||||
|
||||
@DisplayName("WHEN nothing happens THEN the storage is not touched")
|
||||
@Test
|
||||
fun WHEN_nothing_happens_THEN_the_storage_is_not_touched() {
|
||||
fun initializationDoesntAffectStorage() {
|
||||
verifyZeroInteractions(mockFavouriteContentLocalStorage)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN contentId WHEN called THEN storage is called")
|
||||
@Test
|
||||
fun GIVEN_contentId_WHEN_called_THEN_storage_is_called() = runBlockingTest {
|
||||
fun contentIdIsDelegatedToStorage() = runBlockingTest {
|
||||
sut.invoke(ContentId("a"))
|
||||
|
||||
verify(mockFavouriteContentLocalStorage, times(1)).markAsFavourite(ContentId("a"))
|
||||
verifyNoMoreInteractions(mockFavouriteContentLocalStorage)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN throwing local storage WHEN thrown THEN its propagated")
|
||||
@Test
|
||||
fun GIVEN_throwing_local_storage_WHEN_thrown_THEN_its_thrown() = runBlockingTest {
|
||||
whenever(mockFavouriteContentLocalStorage.markAsFavourite(ContentId("a"))).doThrow(RuntimeException())
|
||||
fun storageThrowingIsPropagated() = runBlockingTest {
|
||||
whenever(mockFavouriteContentLocalStorage.markAsFavourite(ContentId("a"))).doThrow(
|
||||
RuntimeException()
|
||||
)
|
||||
|
||||
assertThrows(RuntimeException::class.java) {
|
||||
runBlocking { sut.invoke(ContentId("a")) }
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import kotlinx.coroutines.runBlocking
|
|||
import kotlinx.coroutines.test.runBlockingTest
|
||||
import org.junit.jupiter.api.Assertions.assertThrows
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.kotlin.doThrow
|
||||
import org.mockito.kotlin.mock
|
||||
|
|
@ -25,21 +26,24 @@ internal class FetchContentUseCaseTest {
|
|||
sut = FetchContentUseCase(mockContentRepository)
|
||||
}
|
||||
|
||||
@DisplayName("WHEN nothing happens THEN the storage is not touched")
|
||||
@Test
|
||||
fun WHEN_nothing_happens_THEN_the_storage_is_not_touched() {
|
||||
fun initializationDoesntAffectRepository() {
|
||||
verifyZeroInteractions(mockContentRepository)
|
||||
}
|
||||
|
||||
@DisplayName("WHEN called THEN repository is called")
|
||||
@Test
|
||||
fun WHEN_called_THEN_repository_is_called() = runBlockingTest {
|
||||
fun whenCalledRepositoryIsFetched() = runBlockingTest {
|
||||
sut.invoke()
|
||||
|
||||
verify(mockContentRepository, times(1)).fetch()
|
||||
verifyNoMoreInteractions(mockContentRepository)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN throwing local storage WHEN thrown THEN its thrown")
|
||||
@Test
|
||||
fun GIVEN_throwing_local_storage_WHEN_thrown_THEN_its_thrown() = runBlockingTest {
|
||||
fun whenRepositoryThrowsUseCaseAlsoThrows() = runBlockingTest {
|
||||
whenever(mockContentRepository.fetch()).doThrow(RuntimeException())
|
||||
|
||||
assertThrows(RuntimeException::class.java) {
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import org.fnives.test.showcase.model.content.ImageUrl
|
|||
import org.fnives.test.showcase.model.shared.Resource
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.kotlin.doReturn
|
||||
import org.mockito.kotlin.mock
|
||||
|
|
@ -45,8 +46,9 @@ internal class GetAllContentUseCaseTest {
|
|||
sut = GetAllContentUseCase(mockContentRepository, mockFavouriteContentLocalStorage)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN loading AND empty favourite WHEN observed THEN loading is shown")
|
||||
@Test
|
||||
fun GIVEN_loading_AND_empty_favourite_WHEN_observed_THEN_loading_is_shown() =
|
||||
fun loadingResourceWithNoFavouritesResultsInLoadingResource() =
|
||||
runBlockingTest(testDispatcher) {
|
||||
favouriteContentIdFlow.value = emptyList()
|
||||
contentFlow.value = Resource.Loading()
|
||||
|
|
@ -57,8 +59,9 @@ internal class GetAllContentUseCaseTest {
|
|||
Assertions.assertEquals(listOf(expected), actual)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN loading AND listOfFavourite WHEN observed THEN loading is shown")
|
||||
@Test
|
||||
fun GIVEN_loading_AND_listOfFavourite_WHEN_observed_THEN_loading_is_shown() =
|
||||
fun loadingResourceWithFavouritesResultsInLoadingResource() =
|
||||
runBlockingTest(testDispatcher) {
|
||||
favouriteContentIdFlow.value = listOf(ContentId("a"))
|
||||
contentFlow.value = Resource.Loading()
|
||||
|
|
@ -69,8 +72,9 @@ internal class GetAllContentUseCaseTest {
|
|||
Assertions.assertEquals(listOf(expected), actual)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN error AND empty favourite WHEN observed THEN error is shown")
|
||||
@Test
|
||||
fun GIVEN_error_AND_empty_favourite_WHEN_observed_THEN_error_is_shown() =
|
||||
fun errorResourceWithNoFavouritesResultsInErrorResource() =
|
||||
runBlockingTest(testDispatcher) {
|
||||
favouriteContentIdFlow.value = emptyList()
|
||||
val exception = Throwable()
|
||||
|
|
@ -82,8 +86,9 @@ internal class GetAllContentUseCaseTest {
|
|||
Assertions.assertEquals(listOf(expected), actual)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN error AND listOfFavourite WHEN observed THEN error is shown")
|
||||
@Test
|
||||
fun GIVEN_error_AND_listOfFavourite_WHEN_observed_THEN_error_is_shown() =
|
||||
fun errorResourceWithFavouritesResultsInErrorResource() =
|
||||
runBlockingTest(testDispatcher) {
|
||||
favouriteContentIdFlow.value = listOf(ContentId("b"))
|
||||
val exception = Throwable()
|
||||
|
|
@ -95,8 +100,9 @@ internal class GetAllContentUseCaseTest {
|
|||
Assertions.assertEquals(listOf(expected), actual)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN listOfContent AND empty favourite WHEN observed THEN favourites are returned")
|
||||
@Test
|
||||
fun GIVEN_listOfContent_AND_empty_favourite_WHEN_observed_THEN_favourites_are_returned() =
|
||||
fun successResourceWithNoFavouritesResultsInNoFavouritedItems() =
|
||||
runBlockingTest(testDispatcher) {
|
||||
favouriteContentIdFlow.value = emptyList()
|
||||
val content = Content(ContentId("a"), "b", "c", ImageUrl("d"))
|
||||
|
|
@ -111,8 +117,9 @@ internal class GetAllContentUseCaseTest {
|
|||
Assertions.assertEquals(listOf(expected), actual)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN listOfContent AND other favourite id WHEN observed THEN favourites are returned")
|
||||
@Test
|
||||
fun GIVEN_listOfContent_AND_other_favourite_id_WHEN_observed_THEN_favourites_are_returned() =
|
||||
fun successResourceWithDifferentFavouritesResultsInNoFavouritedItems() =
|
||||
runBlockingTest(testDispatcher) {
|
||||
favouriteContentIdFlow.value = listOf(ContentId("x"))
|
||||
val content = Content(ContentId("a"), "b", "c", ImageUrl("d"))
|
||||
|
|
@ -127,8 +134,9 @@ internal class GetAllContentUseCaseTest {
|
|||
Assertions.assertEquals(listOf(expected), actual)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN listOfContent AND same favourite id WHEN observed THEN favourites are returned")
|
||||
@Test
|
||||
fun GIVEN_listOfContent_AND_same_favourite_id_WHEN_observed_THEN_favourites_are_returned() =
|
||||
fun successResourceWithSameFavouritesResultsInFavouritedItems() =
|
||||
runBlockingTest(testDispatcher) {
|
||||
favouriteContentIdFlow.value = listOf(ContentId("a"))
|
||||
val content = Content(ContentId("a"), "b", "c", ImageUrl("d"))
|
||||
|
|
@ -143,8 +151,9 @@ internal class GetAllContentUseCaseTest {
|
|||
Assertions.assertEquals(listOf(expected), actual)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN loading then data then added favourite WHEN observed THEN loading then correct favourites are returned")
|
||||
@Test
|
||||
fun GIVEN_loading_then_data_then_added_favourite_WHEN_observed_THEN_loading_then_correct_favourites_are_returned() =
|
||||
fun whileLoadingAndAddingItemsReactsProperly() =
|
||||
runBlockingTest(testDispatcher) {
|
||||
favouriteContentIdFlow.value = emptyList()
|
||||
val content = Content(ContentId("a"), "b", "c", ImageUrl("d"))
|
||||
|
|
@ -169,8 +178,9 @@ internal class GetAllContentUseCaseTest {
|
|||
Assertions.assertEquals(expected, actual.await())
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN loading then data then removed favourite WHEN observed THEN loading then correct favourites are returned")
|
||||
@Test
|
||||
fun GIVEN_loading_then_data_then_removed_favourite_WHEN_observed_THEN_loading_then_correct_favourites_are_returned() =
|
||||
fun whileLoadingAndRemovingItemsReactsProperly() =
|
||||
runBlockingTest(testDispatcher) {
|
||||
favouriteContentIdFlow.value = listOf(ContentId("a"))
|
||||
val content = Content(ContentId("a"), "b", "c", ImageUrl("d"))
|
||||
|
|
@ -195,8 +205,9 @@ internal class GetAllContentUseCaseTest {
|
|||
Assertions.assertEquals(expected, actual.await())
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN loading then data then loading WHEN observed THEN loading then correct favourites then loading are returned")
|
||||
@Test
|
||||
fun GIVEN_loading_then_data_then_loading_WHEN_observed_THEN_loading_then_correct_favourites_then_loadingare_returned() =
|
||||
fun loadingThenDataThenLoadingReactsProperly() =
|
||||
runBlockingTest(testDispatcher) {
|
||||
favouriteContentIdFlow.value = listOf(ContentId("a"))
|
||||
val content = Content(ContentId("a"), "b", "c", ImageUrl("d"))
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import org.fnives.test.showcase.core.storage.content.FavouriteContentLocalStorag
|
|||
import org.fnives.test.showcase.model.content.ContentId
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.kotlin.doThrow
|
||||
import org.mockito.kotlin.mock
|
||||
|
|
@ -27,21 +28,24 @@ internal class RemoveContentFromFavouritesUseCaseTest {
|
|||
sut = RemoveContentFromFavouritesUseCase(mockFavouriteContentLocalStorage)
|
||||
}
|
||||
|
||||
@DisplayName("WHEN nothing happens THEN the storage is not touched")
|
||||
@Test
|
||||
fun WHEN_nothing_happens_THEN_the_storage_is_not_touched() {
|
||||
fun initializationDoesntAffectStorage() {
|
||||
verifyZeroInteractions(mockFavouriteContentLocalStorage)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN contentId WHEN called THEN storage is called")
|
||||
@Test
|
||||
fun GIVEN_contentId_WHEN_called_THEN_storage_is_called() = runBlockingTest {
|
||||
fun givenContentIdCallsStorage() = runBlockingTest {
|
||||
sut.invoke(ContentId("a"))
|
||||
|
||||
verify(mockFavouriteContentLocalStorage, times(1)).deleteAsFavourite(ContentId("a"))
|
||||
verifyNoMoreInteractions(mockFavouriteContentLocalStorage)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN throwing local storage WHEN thrown THEN its propogated")
|
||||
@Test
|
||||
fun GIVEN_throwing_local_storage_WHEN_thrown_THEN_its_thrown() = runBlockingTest {
|
||||
fun storageExceptionThrowingIsPropogated() = runBlockingTest {
|
||||
whenever(mockFavouriteContentLocalStorage.deleteAsFavourite(ContentId("a"))).doThrow(RuntimeException())
|
||||
|
||||
Assertions.assertThrows(RuntimeException::class.java) {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import org.fnives.test.showcase.core.storage.UserDataLocalStorage
|
|||
import org.fnives.test.showcase.model.session.Session
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.kotlin.doReturn
|
||||
import org.mockito.kotlin.mock
|
||||
|
|
@ -22,13 +23,15 @@ internal class IsUserLoggedInUseCaseTest {
|
|||
sut = IsUserLoggedInUseCase(mockUserDataLocalStorage)
|
||||
}
|
||||
|
||||
@DisplayName("WHEN nothing is called THEN storage is not called")
|
||||
@Test
|
||||
fun WHEN_nothing_is_called_THEN_storage_is_not_called() {
|
||||
fun creatingDoesntAffectStorage() {
|
||||
verifyZeroInteractions(mockUserDataLocalStorage)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN session data saved WHEN is user logged in checked THEN true is returned")
|
||||
@Test
|
||||
fun GIVEN_session_data_saved_WHEN_is_user_logged_in_checked_THEN_true_is_returned() {
|
||||
fun sessionInStorageResultsInLoggedIn() {
|
||||
whenever(mockUserDataLocalStorage.session).doReturn(Session("a", "b"))
|
||||
|
||||
val actual = sut.invoke()
|
||||
|
|
@ -36,8 +39,9 @@ internal class IsUserLoggedInUseCaseTest {
|
|||
Assertions.assertEquals(true, actual)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN no session data saved WHEN is user logged in checked THEN false is returned")
|
||||
@Test
|
||||
fun GIVEN_no_session_data_saved_WHEN_is_user_logged_in_checked_THEN_false_is_returned() {
|
||||
fun noSessionInStorageResultsInLoggedOut() {
|
||||
whenever(mockUserDataLocalStorage.session).doReturn(null)
|
||||
|
||||
val actual = sut.invoke()
|
||||
|
|
@ -45,8 +49,9 @@ internal class IsUserLoggedInUseCaseTest {
|
|||
Assertions.assertEquals(false, actual)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN no session THEN session THEN no session WHEN is user logged in checked over again THEN every return is correct")
|
||||
@Test
|
||||
fun GIVEN_no_session_THEN_session_THEN_no_session_WHEN_is_user_logged_in_checked_over_again_THEN_every_return_is_correct() {
|
||||
fun multipleSessionSettingsResultsInCorrectResponses() {
|
||||
whenever(mockUserDataLocalStorage.session).doReturn(null)
|
||||
val actual1 = sut.invoke()
|
||||
whenever(mockUserDataLocalStorage.session).doReturn(Session("", ""))
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import org.fnives.test.showcase.core.login.LogoutUseCase
|
|||
import org.fnives.test.showcase.core.storage.UserDataLocalStorage
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.times
|
||||
|
|
@ -36,13 +37,15 @@ internal class LogoutUseCaseTest {
|
|||
testCoreComponent.inject(this)
|
||||
}
|
||||
|
||||
@DisplayName("WHEN no call THEN storage is not interacted")
|
||||
@Test
|
||||
fun WHEN_no_call_THEN_storage_is_not_interacted() {
|
||||
fun initializedDoesntAffectStorage() {
|
||||
verifyZeroInteractions(mockUserDataLocalStorage)
|
||||
}
|
||||
|
||||
@DisplayName("WHEN logout invoked THEN storage is cleared")
|
||||
@Test
|
||||
fun WHEN_logout_invoked_THEN_storage_is_cleared() = runBlockingTest {
|
||||
fun logoutResultsInStorageCleaning() = runBlockingTest {
|
||||
val repositoryBefore = contentRepository
|
||||
|
||||
sut.invoke()
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import org.fnives.test.showcase.model.network.BaseUrl
|
|||
import org.junit.jupiter.api.AfterEach
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.koin.core.context.startKoin
|
||||
import org.koin.core.context.stopKoin
|
||||
|
|
@ -47,13 +48,15 @@ internal class LogoutUseCaseTest : KoinTest {
|
|||
stopKoin()
|
||||
}
|
||||
|
||||
@DisplayName("WHEN no call THEN storage is not interacted")
|
||||
@Test
|
||||
fun WHEN_no_call_THEN_storage_is_not_interacted() {
|
||||
fun initializedDoesntAffectStorage() {
|
||||
verifyZeroInteractions(mockUserDataLocalStorage)
|
||||
}
|
||||
|
||||
@DisplayName("WHEN logout invoked THEN storage is cleared")
|
||||
@Test
|
||||
fun WHEN_logout_invoked_THEN_storage_is_cleared() = runBlockingTest {
|
||||
fun logoutResultsInStorageCleaning() = runBlockingTest {
|
||||
val repositoryBefore = getKoin().get<ContentRepository>()
|
||||
|
||||
sut.invoke()
|
||||
|
|
|
|||
|
|
@ -7,13 +7,15 @@ import org.fnives.test.showcase.model.shared.Resource
|
|||
import org.fnives.test.showcase.network.shared.exceptions.NetworkException
|
||||
import org.fnives.test.showcase.network.shared.exceptions.ParsingException
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
@Suppress("TestFunctionName")
|
||||
internal class AnswerUtilsKtTest {
|
||||
|
||||
@DisplayName("GIVEN network exception thrown WHEN wrapped into answer THEN answer error is returned")
|
||||
@Test
|
||||
fun GIVEN_network_exception_thrown_WHEN_wrapped_into_answer_THEN_answer_error_is_returned() = runBlocking {
|
||||
fun networkExceptionThrownResultsInError() = runBlocking {
|
||||
val exception = NetworkException(Throwable())
|
||||
val expected = Answer.Error<Unit>(exception)
|
||||
|
||||
|
|
@ -22,8 +24,9 @@ internal class AnswerUtilsKtTest {
|
|||
Assertions.assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN parsing exception thrown WHEN wrapped into answer THEN answer error is returned")
|
||||
@Test
|
||||
fun GIVEN_parsing_exception_thrown_WHEN_wrapped_into_answer_THEN_answer_error_is_returned() = runBlocking {
|
||||
fun parsingExceptionThrownResultsInError() = runBlocking {
|
||||
val exception = ParsingException(Throwable())
|
||||
val expected = Answer.Error<Unit>(exception)
|
||||
|
||||
|
|
@ -32,8 +35,9 @@ internal class AnswerUtilsKtTest {
|
|||
Assertions.assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN unexpected throwable thrown WHEN wrapped into answer THEN answer error is returned")
|
||||
@Test
|
||||
fun GIVEN_parsing_throwable_thrown_WHEN_wrapped_into_answer_THEN_answer_error_is_returned() = runBlocking {
|
||||
fun unexpectedExceptionThrownResultsInError() = runBlocking {
|
||||
val exception = Throwable()
|
||||
val expected = Answer.Error<Unit>(UnexpectedException(exception))
|
||||
|
||||
|
|
@ -42,8 +46,9 @@ internal class AnswerUtilsKtTest {
|
|||
Assertions.assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN string WHEN wrapped into answer THEN string answer is returned")
|
||||
@Test
|
||||
fun GIVEN_string_WHEN_wrapped_into_answer_THEN_string_answer_is_returned() = runBlocking {
|
||||
fun stringIsReturnedWrappedIntoSuccess() = runBlocking {
|
||||
val expected = Answer.Success("banan")
|
||||
|
||||
val actual = wrapIntoAnswer { "banan" }
|
||||
|
|
@ -51,15 +56,17 @@ internal class AnswerUtilsKtTest {
|
|||
Assertions.assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN cancellation exception WHEN wrapped into answer THEN cancellation exception is thrown")
|
||||
@Test
|
||||
fun GIVEN_cancellation_exception_WHEN_wrapped_into_answer_THEN_cancellation_exception_is_thrown() {
|
||||
fun cancellationExceptionResultsInThrowingIt() {
|
||||
Assertions.assertThrows(CancellationException::class.java) {
|
||||
runBlocking { wrapIntoAnswer { throw CancellationException() } }
|
||||
}
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN success answer WHEN converted into resource THEN Resource success is returned")
|
||||
@Test
|
||||
fun GIVEN_success_answer_WHEN_converted_into_resource_THEN_Resource_success_is_returned() {
|
||||
fun successAnswerConvertsToSuccessResource() {
|
||||
val expected = Resource.Success("alma")
|
||||
|
||||
val actual = Answer.Success("alma").mapIntoResource()
|
||||
|
|
@ -67,8 +74,9 @@ internal class AnswerUtilsKtTest {
|
|||
Assertions.assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN error answer WHEN converted into resource THEN Resource error is returned")
|
||||
@Test
|
||||
fun GIVEN_error_answer_WHEN_converted_into_resource_THEN_Resource_error_is_returned() {
|
||||
fun errorAnswerConvertsToErrorResource() {
|
||||
val exception = Throwable()
|
||||
val expected = Resource.Error<Unit>(exception)
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package org.fnives.test.showcase.core.storage
|
|||
import org.fnives.test.showcase.model.session.Session
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.kotlin.doReturn
|
||||
import org.mockito.kotlin.mock
|
||||
|
|
@ -23,16 +24,18 @@ internal class NetworkSessionLocalStorageAdapterTest {
|
|||
sut = NetworkSessionLocalStorageAdapter(mockUserDataLocalStorage)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN null as session WHEN saved THEN its delegated")
|
||||
@Test
|
||||
fun GIVEN_null_as_session_WHEN_saved_THEN_its_delegated() {
|
||||
fun settingNullSessionIsDelegated() {
|
||||
sut.session = null
|
||||
|
||||
verify(mockUserDataLocalStorage, times(1)).session = null
|
||||
verifyNoMoreInteractions(mockUserDataLocalStorage)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN session WHEN saved THEN its delegated")
|
||||
@Test
|
||||
fun GIVEN_session_WHEN_saved_THEN_its_delegated() {
|
||||
fun settingDataAsSessionIsDelegated() {
|
||||
val expected = Session("a", "b")
|
||||
|
||||
sut.session = Session("a", "b")
|
||||
|
|
@ -41,8 +44,9 @@ internal class NetworkSessionLocalStorageAdapterTest {
|
|||
verifyNoMoreInteractions(mockUserDataLocalStorage)
|
||||
}
|
||||
|
||||
@DisplayName("WHEN session requested THEN its returned from delegated")
|
||||
@Test
|
||||
fun WHEN_session_requested_THEN_its_returned_from_delegated() {
|
||||
fun gettingSessionReturnsFromDelegate() {
|
||||
val expected = Session("a", "b")
|
||||
whenever(mockUserDataLocalStorage.session).doReturn(expected)
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
|
|||
# https://developer.android.com/topic/libraries/support-library/androidx-rn
|
||||
android.useAndroidX=true
|
||||
# Automatically convert third-party libraries to use AndroidX
|
||||
android.enableJetifier=true
|
||||
android.enableJetifier=false
|
||||
android.jetifier.ignorelist=bcprov-jdk15on
|
||||
# Kotlin code style for this project: "official" or "obsolete":
|
||||
kotlin.code.style=official
|
||||
|
|
@ -1,14 +1,14 @@
|
|||
project.ext {
|
||||
androidx_core_version = "1.7.0"
|
||||
androidx_appcompat_version = "1.3.1"
|
||||
androidx_appcompat_version = "1.4.0"
|
||||
androidx_material_version = "1.4.0"
|
||||
androidx_constraintlayout_version = "2.1.1"
|
||||
androidx_constraintlayout_version = "2.1.2"
|
||||
androidx_livedata_version = "2.4.0"
|
||||
androidx_swiperefreshlayout_version = "1.1.0"
|
||||
androidx_room_version = "2.3.0"
|
||||
androidx_room_version = "2.4.0"
|
||||
activity_ktx_version = "1.4.0"
|
||||
|
||||
coroutines_version = "1.4.3"
|
||||
coroutines_version = "1.5.2"
|
||||
koin_version = "3.1.2"
|
||||
coil_version = "1.1.1"
|
||||
retrofit_version = "2.9.0"
|
||||
|
|
@ -26,5 +26,4 @@ project.ext {
|
|||
testing_junit4_version = "4.13.2"
|
||||
testing_robolectric_version = "4.6.1"
|
||||
testing_espresso_version = "3.4.0"
|
||||
testing_okhttp3_idling_resource_version = "1.0.0"
|
||||
}
|
||||
|
|
@ -35,7 +35,7 @@ class CodeKataLoginRemoteSourceTest {
|
|||
fun badRequestMeansInvalidCredentials() = runBlocking {
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN_internal_error_response_WHEN_request_is_fired_THEN_network_exception_is_thrown")
|
||||
@DisplayName("GIVEN internal error response WHEN request is fired THEN network exception is thrown")
|
||||
@Test
|
||||
fun genericErrorMeansNetworkError() {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import org.fnives.test.showcase.network.shared.exceptions.NetworkException
|
|||
import org.fnives.test.showcase.network.shared.exceptions.ParsingException
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import retrofit2.Response
|
||||
import java.io.IOException
|
||||
|
|
@ -26,8 +27,9 @@ class LoginErrorConverterTest {
|
|||
sut = LoginErrorConverter()
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN throwing lambda WHEN parsing login error THEN network exception is thrown")
|
||||
@Test
|
||||
fun GIVEN_throwing_lambda_WHEN_parsing_login_error_THEN_network_exception_is_thrown() {
|
||||
fun generallyThrowingLambdaResultsInNetworkException() {
|
||||
Assertions.assertThrows(NetworkException::class.java) {
|
||||
runBlocking {
|
||||
sut.invoke { throw IOException() }
|
||||
|
|
@ -35,8 +37,9 @@ class LoginErrorConverterTest {
|
|||
}
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN jsonException throwing lambda WHEN parsing login error THEN network exception is thrown")
|
||||
@Test
|
||||
fun GIVEN_jsonException_throwing_lambda_WHEN_parsing_login_error_THEN_network_exception_is_thrown() {
|
||||
fun jsonDataThrowingLambdaResultsInParsingException() {
|
||||
Assertions.assertThrows(ParsingException::class.java) {
|
||||
runBlocking {
|
||||
sut.invoke { throw JsonDataException("") }
|
||||
|
|
@ -44,8 +47,9 @@ class LoginErrorConverterTest {
|
|||
}
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN 400 error response WHEN parsing login error THEN invalid credentials is returned")
|
||||
@Test
|
||||
fun GIVEN_400_error_response_WHEN_parsing_login_error_THEN_invalid_credentials_is_returned() = runBlockingTest {
|
||||
fun code400ResponseResultsInInvalidCredentials() = runBlockingTest {
|
||||
val expected = LoginStatusResponses.InvalidCredentials
|
||||
|
||||
val actual = sut.invoke {
|
||||
|
|
@ -56,8 +60,9 @@ class LoginErrorConverterTest {
|
|||
Assertions.assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN successful response WHEN parsing login error THEN successful response is returned")
|
||||
@Test
|
||||
fun GIVEN_successful_response_WHEN_parsing_login_error_THEN_successful_response_is_returned() = runBlockingTest {
|
||||
fun successResponseResultsInSessionResponse() = runBlockingTest {
|
||||
val loginResponse = LoginResponse("a", "r")
|
||||
val expectedSession = Session(accessToken = loginResponse.accessToken, refreshToken = loginResponse.refreshToken)
|
||||
val expected = LoginStatusResponses.Success(expectedSession)
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import org.fnives.test.showcase.network.shared.exceptions.NetworkException
|
|||
import org.fnives.test.showcase.network.shared.exceptions.ParsingException
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.RegisterExtension
|
||||
import org.mockito.kotlin.mock
|
||||
|
|
@ -41,8 +42,9 @@ class LoginRemoteSourceRefreshActionImplTest {
|
|||
.inject(this)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN successful response WHEN refresh request is fired THEN session is returned")
|
||||
@Test
|
||||
fun GIVEN_successful_response_WHEN_refresh_request_is_fired_THEN_session() = runBlocking {
|
||||
fun successResponseResultsInSession() = runBlocking {
|
||||
mockServerScenarioSetup.setScenario(RefreshTokenScenario.Success)
|
||||
val expected = ContentData.refreshSuccessResponse
|
||||
|
||||
|
|
@ -51,9 +53,9 @@ class LoginRemoteSourceRefreshActionImplTest {
|
|||
Assertions.assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN successful response WHEN refresh request is fired THEN the request is setup properly")
|
||||
@Test
|
||||
fun GIVEN_successful_response_WHEN_refresh_request_is_fired_THEN_the_request_is_setup_properly() =
|
||||
runBlocking {
|
||||
fun refreshRequestIsSetupProperly() = runBlocking {
|
||||
mockServerScenarioSetup.setScenario(RefreshTokenScenario.Success, false)
|
||||
|
||||
sut.refresh(ContentData.refreshSuccessResponse.refreshToken)
|
||||
|
|
@ -69,8 +71,9 @@ class LoginRemoteSourceRefreshActionImplTest {
|
|||
Assertions.assertEquals("", request.body.readUtf8())
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN internal error response WHEN refresh request is fired THEN network exception is thrown")
|
||||
@Test
|
||||
fun GIVEN_internal_error_response_WHEN_refresh_request_is_fired_THEN_network_exception_is_thrown() {
|
||||
fun generalErrorResponseResultsInNetworkException() {
|
||||
mockServerScenarioSetup.setScenario(RefreshTokenScenario.Error)
|
||||
|
||||
Assertions.assertThrows(NetworkException::class.java) {
|
||||
|
|
@ -78,8 +81,9 @@ class LoginRemoteSourceRefreshActionImplTest {
|
|||
}
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN invalid json response WHEN refresh request is fired THEN network exception is thrown")
|
||||
@Test
|
||||
fun GIVEN_invalid_json_response_WHEN_refresh_request_is_fired_THEN_network_exception_is_thrown() {
|
||||
fun jsonErrorResponseResultsInParsingException() {
|
||||
mockServerScenarioSetup.setScenario(RefreshTokenScenario.UnexpectedJsonAsSuccessResponse)
|
||||
|
||||
Assertions.assertThrows(ParsingException::class.java) {
|
||||
|
|
@ -87,8 +91,9 @@ class LoginRemoteSourceRefreshActionImplTest {
|
|||
}
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN malformed json response WHEN refresh request is fired THEN parsing exception is thrown")
|
||||
@Test
|
||||
fun GIVEN_malformed_json_response_WHEN_refresh_request_is_fired_THEN_network_exception_is_thrown() {
|
||||
fun malformedJsonErrorResponseResultsInParsingException() {
|
||||
mockServerScenarioSetup.setScenario(RefreshTokenScenario.MalformedJson)
|
||||
|
||||
Assertions.assertThrows(ParsingException::class.java) {
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ class LoginRemoteSourceTest {
|
|||
Assertions.assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN_internal_error_response_WHEN_request_is_fired_THEN_network_exception_is_thrown")
|
||||
@DisplayName("GIVEN internal error response WHEN request is fired THEN network exception is thrown")
|
||||
@Test
|
||||
fun genericErrorMeansNetworkError() {
|
||||
mockServerScenarioSetup.setScenario(AuthScenario.GenericError("a", "b"))
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import org.fnives.test.showcase.network.shared.exceptions.ParsingException
|
|||
import org.junit.jupiter.api.AfterEach
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.RegisterExtension
|
||||
import org.koin.core.context.startKoin
|
||||
|
|
@ -53,8 +54,9 @@ class LoginRemoteSourceRefreshActionImplTest : KoinTest {
|
|||
stopKoin()
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN successful response WHEN refresh request is fired THEN session is returned")
|
||||
@Test
|
||||
fun GIVEN_successful_response_WHEN_refresh_request_is_fired_THEN_session() = runBlocking {
|
||||
fun successResponseResultsInSession() = runBlocking {
|
||||
mockServerScenarioSetup.setScenario(RefreshTokenScenario.Success)
|
||||
val expected = ContentData.refreshSuccessResponse
|
||||
|
||||
|
|
@ -63,8 +65,9 @@ class LoginRemoteSourceRefreshActionImplTest : KoinTest {
|
|||
Assertions.assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN successful response WHEN refresh request is fired THEN the request is setup properly")
|
||||
@Test
|
||||
fun GIVEN_successful_response_WHEN_refresh_request_is_fired_THEN_the_request_is_setup_properly() = runBlocking {
|
||||
fun refreshRequestIsSetupProperly() = runBlocking {
|
||||
mockServerScenarioSetup.setScenario(RefreshTokenScenario.Success, false)
|
||||
|
||||
sut.refresh(ContentData.refreshSuccessResponse.refreshToken)
|
||||
|
|
@ -77,8 +80,9 @@ class LoginRemoteSourceRefreshActionImplTest : KoinTest {
|
|||
Assertions.assertEquals("", request.body.readUtf8())
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN internal error response WHEN refresh request is fired THEN network exception is thrown")
|
||||
@Test
|
||||
fun GIVEN_internal_error_response_WHEN_refresh_request_is_fired_THEN_network_exception_is_thrown() {
|
||||
fun generalErrorResponseResultsInNetworkException() {
|
||||
mockServerScenarioSetup.setScenario(RefreshTokenScenario.Error)
|
||||
|
||||
Assertions.assertThrows(NetworkException::class.java) {
|
||||
|
|
@ -86,8 +90,9 @@ class LoginRemoteSourceRefreshActionImplTest : KoinTest {
|
|||
}
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN invalid json response WHEN refresh request is fired THEN network exception is thrown")
|
||||
@Test
|
||||
fun GIVEN_invalid_json_response_WHEN_refresh_request_is_fired_THEN_network_exception_is_thrown() {
|
||||
fun jsonErrorResponseResultsInParsingException() {
|
||||
mockServerScenarioSetup.setScenario(RefreshTokenScenario.UnexpectedJsonAsSuccessResponse)
|
||||
|
||||
Assertions.assertThrows(ParsingException::class.java) {
|
||||
|
|
@ -95,8 +100,9 @@ class LoginRemoteSourceRefreshActionImplTest : KoinTest {
|
|||
}
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN malformed json response WHEN refresh request is fired THEN parsing exception is thrown")
|
||||
@Test
|
||||
fun GIVEN_malformed_json_response_WHEN_refresh_request_is_fired_THEN_network_exception_is_thrown() {
|
||||
fun malformedJsonErrorResponseResultsInParsingException() {
|
||||
mockServerScenarioSetup.setScenario(RefreshTokenScenario.MalformedJson)
|
||||
|
||||
Assertions.assertThrows(ParsingException::class.java) {
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ class LoginRemoteSourceTest : KoinTest {
|
|||
Assertions.assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN_internal_error_response_WHEN_request_is_fired_THEN_network_exception_is_thrown")
|
||||
@DisplayName("GIVEN internal error response WHEN request is fired THEN network exception is thrown")
|
||||
@Test
|
||||
fun genericErrorMeansNetworkError() {
|
||||
mockServerScenarioSetup.setScenario(AuthScenario.GenericError("a", "b"))
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ class CodeKataSessionExpirationTest : KoinTest {
|
|||
mockWebServer.shutdown()
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN_401_THEN_refresh_token_ok_response_WHEN_content_requested_THE_tokens_are_refreshed_and_request_retried_with_new_tokens")
|
||||
@DisplayName("GIVEN 401 THEN refresh token ok response WHEN content requested THE tokens are refreshed and request retried with new tokens")
|
||||
@Test
|
||||
fun successRefreshResultsInRequestRetry() = runBlocking {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import org.fnives.test.showcase.network.shared.exceptions.NetworkException
|
|||
import org.fnives.test.showcase.network.shared.exceptions.ParsingException
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.RegisterExtension
|
||||
import org.koin.test.inject
|
||||
|
|
@ -44,8 +45,9 @@ class ContentRemoteSourceImplTest {
|
|||
.inject(this)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN successful response WHEN getting content THEN its parsed and returned correctly")
|
||||
@Test
|
||||
fun GIVEN_successful_response_WHEN_getting_content_THEN_its_parsed_and_returned_correctly() = runBlocking {
|
||||
fun successResponseParsing() = runBlocking {
|
||||
whenever(mockNetworkSessionLocalStorage.session).doReturn(ContentData.loginSuccessResponse)
|
||||
mockServerScenarioSetup.setScenario(ContentScenario.Success(false))
|
||||
val expected = ContentData.contentSuccess
|
||||
|
|
@ -55,8 +57,9 @@ class ContentRemoteSourceImplTest {
|
|||
Assertions.assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN successful response WHEN getting content THEN the request is setup properly")
|
||||
@Test
|
||||
fun GIVEN_successful_response_WHEN_getting_content_THEN_the_request_is_setup_properly() = runBlocking {
|
||||
fun successResponseRequestIsCorrect() = runBlocking {
|
||||
whenever(mockNetworkSessionLocalStorage.session).doReturn(ContentData.loginSuccessResponse)
|
||||
mockServerScenarioSetup.setScenario(ContentScenario.Success(false), false)
|
||||
|
||||
|
|
@ -70,8 +73,9 @@ class ContentRemoteSourceImplTest {
|
|||
Assertions.assertEquals("", request.body.readUtf8())
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN response with missing Field WHEN getting content THEN invalid is ignored others are returned")
|
||||
@Test
|
||||
fun GIVEN_response_with_missing_Field_WHEN_getting_content_THEN_invalid_is_ignored_others_are_returned() = runBlocking {
|
||||
fun dataMissingFieldIsIgnored() = runBlocking {
|
||||
whenever(mockNetworkSessionLocalStorage.session).doReturn(ContentData.loginSuccessResponse)
|
||||
mockServerScenarioSetup.setScenario(ContentScenario.SuccessWithMissingFields(false))
|
||||
|
||||
|
|
@ -82,8 +86,9 @@ class ContentRemoteSourceImplTest {
|
|||
Assertions.assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN error response WHEN getting content THEN network request is thrown")
|
||||
@Test
|
||||
fun GIVEN_error_response_WHEN_getting_content_THEN_network_request_is_thrown() {
|
||||
fun errorResponseResultsInNetworkException() {
|
||||
whenever(mockNetworkSessionLocalStorage.session).doReturn(ContentData.loginSuccessResponse)
|
||||
mockServerScenarioSetup.setScenario(ContentScenario.Error(false))
|
||||
|
||||
|
|
@ -92,8 +97,9 @@ class ContentRemoteSourceImplTest {
|
|||
}
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN unexpected json response WHEN getting content THEN parsing request is thrown")
|
||||
@Test
|
||||
fun GIVEN_unexpected_json_response_WHEN_getting_content_THEN_parsing_request_is_thrown() {
|
||||
fun unexpectedJSONResultsInParsingException() {
|
||||
whenever(mockNetworkSessionLocalStorage.session).doReturn(ContentData.loginSuccessResponse)
|
||||
mockServerScenarioSetup.setScenario(ContentScenario.UnexpectedJsonAsSuccessResponse(false))
|
||||
|
||||
|
|
@ -102,8 +108,9 @@ class ContentRemoteSourceImplTest {
|
|||
}
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN malformed json response WHEN getting content THEN parsing request is thrown")
|
||||
@Test
|
||||
fun GIVEN_malformed_json_response_WHEN_getting_content_THEN_parsing_request_is_thrown() {
|
||||
fun malformedJSONResultsInParsingException() {
|
||||
whenever(mockNetworkSessionLocalStorage.session).doReturn(ContentData.loginSuccessResponse)
|
||||
mockServerScenarioSetup.setScenario(ContentScenario.MalformedJsonAsSuccessResponse(false))
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ class SessionExpirationTest {
|
|||
.inject(this)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN_401_THEN_refresh_token_ok_response_WHEN_content_requested_THE_tokens_are_refreshed_and_request_retried_with_new_tokens")
|
||||
@DisplayName("GIVEN 401 THEN refresh token ok response WHEN content requested THE tokens are refreshed and request retried with new tokens")
|
||||
@Test
|
||||
fun successRefreshResultsInRequestRetry() = runBlocking {
|
||||
var sessionToReturnByMock: Session? = ContentData.loginSuccessResponse
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import org.fnives.test.showcase.network.shared.exceptions.ParsingException
|
|||
import org.junit.jupiter.api.AfterEach
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.RegisterExtension
|
||||
import org.koin.core.context.startKoin
|
||||
|
|
@ -55,8 +56,9 @@ class ContentRemoteSourceImplTest : KoinTest {
|
|||
stopKoin()
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN successful response WHEN getting content THEN its parsed and returned correctly")
|
||||
@Test
|
||||
fun GIVEN_successful_response_WHEN_getting_content_THEN_its_parsed_and_returned_correctly() = runBlocking {
|
||||
fun successResponseParsing() = runBlocking {
|
||||
whenever(mockNetworkSessionLocalStorage.session).doReturn(ContentData.loginSuccessResponse)
|
||||
mockServerScenarioSetup.setScenario(ContentScenario.Success(false))
|
||||
val expected = ContentData.contentSuccess
|
||||
|
|
@ -66,8 +68,9 @@ class ContentRemoteSourceImplTest : KoinTest {
|
|||
Assertions.assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN successful response WHEN getting content THEN the request is setup properly")
|
||||
@Test
|
||||
fun GIVEN_successful_response_WHEN_getting_content_THEN_the_request_is_setup_properly() = runBlocking {
|
||||
fun successResponseRequestIsCorrect() = runBlocking {
|
||||
whenever(mockNetworkSessionLocalStorage.session).doReturn(ContentData.loginSuccessResponse)
|
||||
mockServerScenarioSetup.setScenario(ContentScenario.Success(false), false)
|
||||
|
||||
|
|
@ -81,8 +84,9 @@ class ContentRemoteSourceImplTest : KoinTest {
|
|||
Assertions.assertEquals("", request.body.readUtf8())
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN response with missing Field WHEN getting content THEN invalid is ignored others are returned")
|
||||
@Test
|
||||
fun GIVEN_response_with_missing_Field_WHEN_getting_content_THEN_invalid_is_ignored_others_are_returned() = runBlocking {
|
||||
fun dataMissingFieldIsIgnored() = runBlocking {
|
||||
whenever(mockNetworkSessionLocalStorage.session).doReturn(ContentData.loginSuccessResponse)
|
||||
mockServerScenarioSetup.setScenario(ContentScenario.SuccessWithMissingFields(false))
|
||||
|
||||
|
|
@ -93,8 +97,9 @@ class ContentRemoteSourceImplTest : KoinTest {
|
|||
Assertions.assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN error response WHEN getting content THEN network request is thrown")
|
||||
@Test
|
||||
fun GIVEN_error_response_WHEN_getting_content_THEN_network_request_is_thrown() {
|
||||
fun errorResponseResultsInNetworkException() {
|
||||
whenever(mockNetworkSessionLocalStorage.session).doReturn(ContentData.loginSuccessResponse)
|
||||
mockServerScenarioSetup.setScenario(ContentScenario.Error(false))
|
||||
|
||||
|
|
@ -103,8 +108,9 @@ class ContentRemoteSourceImplTest : KoinTest {
|
|||
}
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN unexpected json response WHEN getting content THEN parsing request is thrown")
|
||||
@Test
|
||||
fun GIVEN_unexpected_json_response_WHEN_getting_content_THEN_parsing_request_is_thrown() {
|
||||
fun unexpectedJSONResultsInParsingException() {
|
||||
whenever(mockNetworkSessionLocalStorage.session).doReturn(ContentData.loginSuccessResponse)
|
||||
mockServerScenarioSetup.setScenario(ContentScenario.UnexpectedJsonAsSuccessResponse(false))
|
||||
|
||||
|
|
@ -113,8 +119,9 @@ class ContentRemoteSourceImplTest : KoinTest {
|
|||
}
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN malformed json response WHEN getting content THEN parsing request is thrown")
|
||||
@Test
|
||||
fun GIVEN_malformed_json_response_WHEN_getting_content_THEN_parsing_request_is_thrown() {
|
||||
fun malformedJSONResultsInParsingException() {
|
||||
whenever(mockNetworkSessionLocalStorage.session).doReturn(ContentData.loginSuccessResponse)
|
||||
mockServerScenarioSetup.setScenario(ContentScenario.MalformedJsonAsSuccessResponse(false))
|
||||
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ class SessionExpirationTest : KoinTest {
|
|||
stopKoin()
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN_401_THEN_refresh_token_ok_response_WHEN_content_requested_THE_tokens_are_refreshed_and_request_retried_with_new_tokens")
|
||||
@DisplayName("GIVEN 401 THEN refresh token ok response WHEN content requested THE tokens are refreshed and request retried with new tokens")
|
||||
@Test
|
||||
fun successRefreshResultsInRequestRetry() = runBlocking {
|
||||
var sessionToReturnByMock: Session? = ContentData.loginSuccessResponse
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue