Merge pull request #76 from fknives/fix-database-swapping-on-older-api-levels
Fix swapping out Database in tests
This commit is contained in:
commit
e05d2feb0c
29 changed files with 125 additions and 113 deletions
|
|
@ -12,12 +12,12 @@ import androidx.test.runner.AndroidJUnit4
|
||||||
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
||||||
import org.fnives.test.showcase.R
|
import org.fnives.test.showcase.R
|
||||||
import org.fnives.test.showcase.network.testutil.NetworkTestConfigurationHelper
|
import org.fnives.test.showcase.network.testutil.NetworkTestConfigurationHelper
|
||||||
import org.fnives.test.showcase.storage.database.DatabaseInitialization
|
|
||||||
import org.fnives.test.showcase.testutils.idling.CompositeDisposable
|
import org.fnives.test.showcase.testutils.idling.CompositeDisposable
|
||||||
import org.fnives.test.showcase.testutils.idling.Disposable
|
import org.fnives.test.showcase.testutils.idling.Disposable
|
||||||
import org.fnives.test.showcase.testutils.idling.IdlingResourceDisposable
|
import org.fnives.test.showcase.testutils.idling.IdlingResourceDisposable
|
||||||
import org.fnives.test.showcase.testutils.idling.OkHttp3IdlingResource
|
import org.fnives.test.showcase.testutils.idling.OkHttp3IdlingResource
|
||||||
import org.fnives.test.showcase.testutils.idling.loopMainThreadFor
|
import org.fnives.test.showcase.testutils.idling.loopMainThreadFor
|
||||||
|
import org.fnives.test.showcase.testutils.storage.TestDatabaseInitialization
|
||||||
import org.fnives.test.showcase.ui.splash.SplashActivity
|
import org.fnives.test.showcase.ui.splash.SplashActivity
|
||||||
import org.hamcrest.Description
|
import org.hamcrest.Description
|
||||||
import org.hamcrest.Matcher
|
import org.hamcrest.Matcher
|
||||||
|
|
@ -45,7 +45,7 @@ class LoginLogoutEndToEndTest {
|
||||||
@Before
|
@Before
|
||||||
fun before() {
|
fun before() {
|
||||||
/** Needed to add the dispatcher to the Database */
|
/** Needed to add the dispatcher to the Database */
|
||||||
DatabaseInitialization.dispatcher = UnconfinedTestDispatcher()
|
TestDatabaseInitialization.overwriteDatabaseInitialization(UnconfinedTestDispatcher())
|
||||||
|
|
||||||
/** Needed to register the Okhttp as Idling resource, so Espresso actually waits for the response.*/
|
/** Needed to register the Okhttp as Idling resource, so Espresso actually waits for the response.*/
|
||||||
val idlingResources = NetworkTestConfigurationHelper.getOkHttpClients()
|
val idlingResources = NetworkTestConfigurationHelper.getOkHttpClients()
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ import org.fnives.test.showcase.R
|
||||||
fun SplashScreen() {
|
fun SplashScreen() {
|
||||||
Box(Modifier.fillMaxSize().background(colorResource(R.color.purple_700)), contentAlignment = Alignment.Center) {
|
Box(Modifier.fillMaxSize().background(colorResource(R.color.purple_700)), contentAlignment = Alignment.Center) {
|
||||||
Image(
|
Image(
|
||||||
painter = painterResource(R.drawable.ic_launcher_foreground),
|
painter = painterResource(R.mipmap.ic_launcher_round),
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
modifier = Modifier.size(120.dp)
|
modifier = Modifier.size(120.dp)
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ import kotlinx.coroutines.test.runTest
|
||||||
import org.fnives.test.showcase.core.integration.fake.FakeFavouriteContentLocalStorage
|
import org.fnives.test.showcase.core.integration.fake.FakeFavouriteContentLocalStorage
|
||||||
import org.fnives.test.showcase.core.storage.content.FavouriteContentLocalStorage
|
import org.fnives.test.showcase.core.storage.content.FavouriteContentLocalStorage
|
||||||
import org.fnives.test.showcase.model.content.ContentId
|
import org.fnives.test.showcase.model.content.ContentId
|
||||||
import org.fnives.test.showcase.storage.database.DatabaseInitialization
|
import org.fnives.test.showcase.testutils.storage.TestDatabaseInitialization
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
import org.junit.Assert
|
import org.junit.Assert
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
|
|
@ -36,7 +36,7 @@ internal class FavouriteContentLocalStorageImplInstrumentedTest(
|
||||||
@Before
|
@Before
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
testDispatcher = StandardTestDispatcher()
|
testDispatcher = StandardTestDispatcher()
|
||||||
DatabaseInitialization.dispatcher = testDispatcher
|
TestDatabaseInitialization.overwriteDatabaseInitialization(testDispatcher)
|
||||||
sut = favouriteContentLocalStorageFactory()
|
sut = favouriteContentLocalStorageFactory()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,13 +14,13 @@ import org.fnives.test.showcase.R
|
||||||
import org.fnives.test.showcase.network.mockserver.MockServerScenarioSetup
|
import org.fnives.test.showcase.network.mockserver.MockServerScenarioSetup
|
||||||
import org.fnives.test.showcase.network.mockserver.scenario.auth.AuthScenario
|
import org.fnives.test.showcase.network.mockserver.scenario.auth.AuthScenario
|
||||||
import org.fnives.test.showcase.network.testutil.NetworkTestConfigurationHelper
|
import org.fnives.test.showcase.network.testutil.NetworkTestConfigurationHelper
|
||||||
import org.fnives.test.showcase.storage.database.DatabaseInitialization
|
|
||||||
import org.fnives.test.showcase.testutils.idling.CompositeDisposable
|
import org.fnives.test.showcase.testutils.idling.CompositeDisposable
|
||||||
import org.fnives.test.showcase.testutils.idling.Disposable
|
import org.fnives.test.showcase.testutils.idling.Disposable
|
||||||
import org.fnives.test.showcase.testutils.idling.IdlingResourceDisposable
|
import org.fnives.test.showcase.testutils.idling.IdlingResourceDisposable
|
||||||
import org.fnives.test.showcase.testutils.idling.MainDispatcherTestRule.Companion.advanceUntilIdleWithIdlingResources
|
import org.fnives.test.showcase.testutils.idling.MainDispatcherTestRule.Companion.advanceUntilIdleWithIdlingResources
|
||||||
import org.fnives.test.showcase.testutils.idling.OkHttp3IdlingResource
|
import org.fnives.test.showcase.testutils.idling.OkHttp3IdlingResource
|
||||||
import org.fnives.test.showcase.testutils.safeClose
|
import org.fnives.test.showcase.testutils.safeClose
|
||||||
|
import org.fnives.test.showcase.testutils.storage.TestDatabaseInitialization
|
||||||
import org.fnives.test.showcase.ui.auth.AuthActivity
|
import org.fnives.test.showcase.ui.auth.AuthActivity
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
|
|
@ -45,7 +45,7 @@ class RobolectricAuthActivityInstrumentedTest : KoinTest {
|
||||||
val dispatcher = StandardTestDispatcher()
|
val dispatcher = StandardTestDispatcher()
|
||||||
Dispatchers.setMain(dispatcher)
|
Dispatchers.setMain(dispatcher)
|
||||||
testDispatcher = dispatcher
|
testDispatcher = dispatcher
|
||||||
DatabaseInitialization.dispatcher = dispatcher
|
TestDatabaseInitialization.overwriteDatabaseInitialization(dispatcher)
|
||||||
|
|
||||||
mockServerScenarioSetup = NetworkTestConfigurationHelper.startWithHTTPSMockWebServer()
|
mockServerScenarioSetup = NetworkTestConfigurationHelper.startWithHTTPSMockWebServer()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
package org.fnives.test.showcase.storage.database
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import androidx.room.Room
|
|
||||||
import kotlinx.coroutines.CoroutineDispatcher
|
|
||||||
import kotlinx.coroutines.asExecutor
|
|
||||||
import org.fnives.test.showcase.storage.LocalDatabase
|
|
||||||
|
|
||||||
object DatabaseInitialization {
|
|
||||||
|
|
||||||
lateinit var dispatcher: CoroutineDispatcher
|
|
||||||
|
|
||||||
fun create(context: Context): LocalDatabase {
|
|
||||||
val executor = dispatcher.asExecutor()
|
|
||||||
return Room.inMemoryDatabaseBuilder(context, LocalDatabase::class.java)
|
|
||||||
.setTransactionExecutor(executor)
|
|
||||||
.setQueryExecutor(executor)
|
|
||||||
.allowMainThreadQueries()
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -3,8 +3,8 @@ package org.fnives.test.showcase.testutils.idling
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.test.StandardTestDispatcher
|
import kotlinx.coroutines.test.StandardTestDispatcher
|
||||||
import kotlinx.coroutines.test.TestDispatcher
|
import kotlinx.coroutines.test.TestDispatcher
|
||||||
import org.fnives.test.showcase.storage.database.DatabaseInitialization
|
|
||||||
import org.fnives.test.showcase.testutils.runOnUIAwaitOnCurrent
|
import org.fnives.test.showcase.testutils.runOnUIAwaitOnCurrent
|
||||||
|
import org.fnives.test.showcase.testutils.storage.TestDatabaseInitialization
|
||||||
import org.junit.rules.TestRule
|
import org.junit.rules.TestRule
|
||||||
import org.junit.runner.Description
|
import org.junit.runner.Description
|
||||||
import org.junit.runners.model.Statement
|
import org.junit.runners.model.Statement
|
||||||
|
|
@ -20,7 +20,7 @@ class DispatcherTestRule : TestRule {
|
||||||
override fun evaluate() {
|
override fun evaluate() {
|
||||||
val dispatcher = StandardTestDispatcher()
|
val dispatcher = StandardTestDispatcher()
|
||||||
testDispatcher = dispatcher
|
testDispatcher = dispatcher
|
||||||
DatabaseInitialization.dispatcher = dispatcher
|
TestDatabaseInitialization.overwriteDatabaseInitialization(dispatcher)
|
||||||
base.evaluate()
|
base.evaluate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ import kotlinx.coroutines.test.StandardTestDispatcher
|
||||||
import kotlinx.coroutines.test.TestDispatcher
|
import kotlinx.coroutines.test.TestDispatcher
|
||||||
import kotlinx.coroutines.test.resetMain
|
import kotlinx.coroutines.test.resetMain
|
||||||
import kotlinx.coroutines.test.setMain
|
import kotlinx.coroutines.test.setMain
|
||||||
import org.fnives.test.showcase.storage.database.DatabaseInitialization
|
|
||||||
import org.fnives.test.showcase.testutils.runOnUIAwaitOnCurrent
|
import org.fnives.test.showcase.testutils.runOnUIAwaitOnCurrent
|
||||||
|
import org.fnives.test.showcase.testutils.storage.TestDatabaseInitialization
|
||||||
import org.junit.rules.TestRule
|
import org.junit.rules.TestRule
|
||||||
import org.junit.runner.Description
|
import org.junit.runner.Description
|
||||||
import org.junit.runners.model.Statement
|
import org.junit.runners.model.Statement
|
||||||
|
|
@ -24,7 +24,7 @@ class MainDispatcherTestRule : TestRule {
|
||||||
val dispatcher = StandardTestDispatcher()
|
val dispatcher = StandardTestDispatcher()
|
||||||
Dispatchers.setMain(dispatcher)
|
Dispatchers.setMain(dispatcher)
|
||||||
testDispatcher = dispatcher
|
testDispatcher = dispatcher
|
||||||
DatabaseInitialization.dispatcher = dispatcher
|
TestDatabaseInitialization.overwriteDatabaseInitialization(dispatcher)
|
||||||
try {
|
try {
|
||||||
base.evaluate()
|
base.evaluate()
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
package org.fnives.test.showcase.testutils.storage
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.room.Room
|
||||||
|
import kotlinx.coroutines.CoroutineDispatcher
|
||||||
|
import kotlinx.coroutines.asExecutor
|
||||||
|
import org.fnives.test.showcase.storage.LocalDatabase
|
||||||
|
import org.koin.android.ext.koin.androidContext
|
||||||
|
import org.koin.core.context.loadKoinModules
|
||||||
|
import org.koin.dsl.module
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reloads the Database Koin module, so it uses the inMemory database with the switched out Executors.
|
||||||
|
*/
|
||||||
|
object TestDatabaseInitialization {
|
||||||
|
|
||||||
|
fun create(context: Context, dispatcher: CoroutineDispatcher): LocalDatabase {
|
||||||
|
val executor = dispatcher.asExecutor()
|
||||||
|
return Room.inMemoryDatabaseBuilder(context, LocalDatabase::class.java)
|
||||||
|
.setTransactionExecutor(executor)
|
||||||
|
.setQueryExecutor(executor)
|
||||||
|
.allowMainThreadQueries()
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun overwriteDatabaseInitialization(dispatcher: CoroutineDispatcher) {
|
||||||
|
loadKoinModules(
|
||||||
|
module {
|
||||||
|
single { create(androidContext(), dispatcher) }
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -8,6 +8,7 @@ import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
||||||
import kotlinx.coroutines.test.resetMain
|
import kotlinx.coroutines.test.resetMain
|
||||||
import kotlinx.coroutines.test.setMain
|
import kotlinx.coroutines.test.setMain
|
||||||
import org.fnives.test.showcase.storage.database.DatabaseInitialization
|
import org.fnives.test.showcase.storage.database.DatabaseInitialization
|
||||||
|
import org.fnives.test.showcase.testutils.storage.TestDatabaseInitialization
|
||||||
import org.junit.rules.TestRule
|
import org.junit.rules.TestRule
|
||||||
import org.junit.runner.Description
|
import org.junit.runner.Description
|
||||||
import org.junit.runners.model.Statement
|
import org.junit.runners.model.Statement
|
||||||
|
|
@ -28,7 +29,7 @@ class PlainMainDispatcherRule(private val useStandard: Boolean = true) : TestRul
|
||||||
try {
|
try {
|
||||||
val dispatcher = if (useStandard) StandardTestDispatcher() else UnconfinedTestDispatcher()
|
val dispatcher = if (useStandard) StandardTestDispatcher() else UnconfinedTestDispatcher()
|
||||||
Dispatchers.setMain(dispatcher)
|
Dispatchers.setMain(dispatcher)
|
||||||
DatabaseInitialization.dispatcher = dispatcher
|
TestDatabaseInitialization.overwriteDatabaseInitialization(dispatcher)
|
||||||
_testDispatcher = dispatcher
|
_testDispatcher = dispatcher
|
||||||
base.evaluate()
|
base.evaluate()
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -6,14 +6,13 @@ import kotlinx.coroutines.test.StandardTestDispatcher
|
||||||
import kotlinx.coroutines.test.TestDispatcher
|
import kotlinx.coroutines.test.TestDispatcher
|
||||||
import kotlinx.coroutines.test.resetMain
|
import kotlinx.coroutines.test.resetMain
|
||||||
import kotlinx.coroutines.test.setMain
|
import kotlinx.coroutines.test.setMain
|
||||||
import org.fnives.test.showcase.storage.database.DatabaseInitialization
|
|
||||||
import org.fnives.test.showcase.testutils.TestMainDispatcher.Companion.testDispatcher
|
import org.fnives.test.showcase.testutils.TestMainDispatcher.Companion.testDispatcher
|
||||||
import org.junit.jupiter.api.extension.AfterEachCallback
|
import org.junit.jupiter.api.extension.AfterEachCallback
|
||||||
import org.junit.jupiter.api.extension.BeforeEachCallback
|
import org.junit.jupiter.api.extension.BeforeEachCallback
|
||||||
import org.junit.jupiter.api.extension.ExtensionContext
|
import org.junit.jupiter.api.extension.ExtensionContext
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom Junit5 Extension which replaces the [DatabaseInitialization]'s dispatcher and main dispatcher with a [TestDispatcher]
|
* Custom Junit5 Extension which replaces the main dispatcher with a [TestDispatcher]
|
||||||
*
|
*
|
||||||
* One can access the test dispatcher via [testDispatcher] static getter.
|
* One can access the test dispatcher via [testDispatcher] static getter.
|
||||||
*/
|
*/
|
||||||
|
|
@ -23,7 +22,6 @@ class TestMainDispatcher : BeforeEachCallback, AfterEachCallback {
|
||||||
override fun beforeEach(context: ExtensionContext?) {
|
override fun beforeEach(context: ExtensionContext?) {
|
||||||
val testDispatcher = StandardTestDispatcher()
|
val testDispatcher = StandardTestDispatcher()
|
||||||
privateTestDispatcher = testDispatcher
|
privateTestDispatcher = testDispatcher
|
||||||
DatabaseInitialization.dispatcher = testDispatcher
|
|
||||||
Dispatchers.setMain(testDispatcher)
|
Dispatchers.setMain(testDispatcher)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,8 @@ import org.mockito.kotlin.doReturn
|
||||||
import org.mockito.kotlin.mock
|
import org.mockito.kotlin.mock
|
||||||
import org.mockito.kotlin.times
|
import org.mockito.kotlin.times
|
||||||
import org.mockito.kotlin.verify
|
import org.mockito.kotlin.verify
|
||||||
|
import org.mockito.kotlin.verifyNoInteractions
|
||||||
import org.mockito.kotlin.verifyNoMoreInteractions
|
import org.mockito.kotlin.verifyNoMoreInteractions
|
||||||
import org.mockito.kotlin.verifyZeroInteractions
|
|
||||||
import org.mockito.kotlin.whenever
|
import org.mockito.kotlin.whenever
|
||||||
|
|
||||||
@Suppress("TestFunctionName")
|
@Suppress("TestFunctionName")
|
||||||
|
|
@ -150,7 +150,7 @@ internal class MainViewModelTest {
|
||||||
sut.onRefresh()
|
sut.onRefresh()
|
||||||
testScheduler.advanceUntilIdle()
|
testScheduler.advanceUntilIdle()
|
||||||
|
|
||||||
verifyZeroInteractions(mockFetchContentUseCase)
|
verifyNoInteractions(mockFetchContentUseCase)
|
||||||
}
|
}
|
||||||
|
|
||||||
@DisplayName("GIVEN non loading viewModel WHEN refreshing THEN usecase is called")
|
@DisplayName("GIVEN non loading viewModel WHEN refreshing THEN usecase is called")
|
||||||
|
|
@ -209,8 +209,8 @@ internal class MainViewModelTest {
|
||||||
sut.onFavouriteToggleClicked(ContentId("c"))
|
sut.onFavouriteToggleClicked(ContentId("c"))
|
||||||
testScheduler.advanceUntilIdle()
|
testScheduler.advanceUntilIdle()
|
||||||
|
|
||||||
verifyZeroInteractions(mockRemoveContentFromFavouritesUseCase)
|
verifyNoInteractions(mockRemoveContentFromFavouritesUseCase)
|
||||||
verifyZeroInteractions(mockAddContentToFavouriteUseCase)
|
verifyNoInteractions(mockAddContentToFavouriteUseCase)
|
||||||
}
|
}
|
||||||
|
|
||||||
@DisplayName("GIVEN success content list viewModel WHEN toggling a favourite contentId THEN remove favourite usecase is called")
|
@DisplayName("GIVEN success content list viewModel WHEN toggling a favourite contentId THEN remove favourite usecase is called")
|
||||||
|
|
@ -229,7 +229,7 @@ internal class MainViewModelTest {
|
||||||
|
|
||||||
runBlocking { verify(mockRemoveContentFromFavouritesUseCase, times(1)).invoke(ContentId("b")) }
|
runBlocking { verify(mockRemoveContentFromFavouritesUseCase, times(1)).invoke(ContentId("b")) }
|
||||||
verifyNoMoreInteractions(mockRemoveContentFromFavouritesUseCase)
|
verifyNoMoreInteractions(mockRemoveContentFromFavouritesUseCase)
|
||||||
verifyZeroInteractions(mockAddContentToFavouriteUseCase)
|
verifyNoInteractions(mockAddContentToFavouriteUseCase)
|
||||||
}
|
}
|
||||||
|
|
||||||
@DisplayName("GIVEN success content list viewModel WHEN toggling a not favourite contentId THEN add favourite usecase is called")
|
@DisplayName("GIVEN success content list viewModel WHEN toggling a not favourite contentId THEN add favourite usecase is called")
|
||||||
|
|
@ -246,7 +246,7 @@ internal class MainViewModelTest {
|
||||||
sut.onFavouriteToggleClicked(ContentId("a"))
|
sut.onFavouriteToggleClicked(ContentId("a"))
|
||||||
testScheduler.advanceUntilIdle()
|
testScheduler.advanceUntilIdle()
|
||||||
|
|
||||||
verifyZeroInteractions(mockRemoveContentFromFavouritesUseCase)
|
verifyNoInteractions(mockRemoveContentFromFavouritesUseCase)
|
||||||
runBlocking { verify(mockAddContentToFavouriteUseCase, times(1)).invoke(ContentId("a")) }
|
runBlocking { verify(mockAddContentToFavouriteUseCase, times(1)).invoke(ContentId("a")) }
|
||||||
verifyNoMoreInteractions(mockAddContentToFavouriteUseCase)
|
verifyNoMoreInteractions(mockAddContentToFavouriteUseCase)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -162,7 +162,7 @@ fun withoutSessionTheUserIsNotLoggedIn() = runTest {
|
||||||
val actual = isUserLoggedInUseCase.invoke()
|
val actual = isUserLoggedInUseCase.invoke()
|
||||||
|
|
||||||
Assertions.assertFalse(actual, "User is expected to be not logged in")
|
Assertions.assertFalse(actual, "User is expected to be not logged in")
|
||||||
verifyZeroInteractions(mockSessionExpirationListener)
|
verifyNoInteractions(mockSessionExpirationListener)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -187,7 +187,7 @@ And just verify:
|
||||||
Assertions.assertEquals(Answer.Success(LoginStatus.SUCCESS), answer)
|
Assertions.assertEquals(Answer.Success(LoginStatus.SUCCESS), answer)
|
||||||
Assertions.assertTrue(actual, "User is expected to be logged in")
|
Assertions.assertTrue(actual, "User is expected to be logged in")
|
||||||
Assertions.assertEquals(expectedSession, fakeUserDataLocalStorage.session)
|
Assertions.assertEquals(expectedSession, fakeUserDataLocalStorage.session)
|
||||||
verifyZeroInteractions(mockSessionExpirationListener)
|
verifyNoInteractions(mockSessionExpirationListener)
|
||||||
```
|
```
|
||||||
|
|
||||||
With this, looks like our Integration works correctly. Requests are called, proper response is received, login state is changed.
|
With this, looks like our Integration works correctly. Requests are called, proper response is received, login state is changed.
|
||||||
|
|
@ -214,7 +214,7 @@ And do our verifications, aka not logged in, not session expired and the correct
|
||||||
Assertions.assertEquals(Answer.Success(loginError), answer)
|
Assertions.assertEquals(Answer.Success(loginError), answer)
|
||||||
Assertions.assertFalse(actual, "User is expected to be not logged in")
|
Assertions.assertFalse(actual, "User is expected to be not logged in")
|
||||||
Assertions.assertEquals(null, fakeUserDataLocalStorage.session)
|
Assertions.assertEquals(null, fakeUserDataLocalStorage.session)
|
||||||
verifyZeroInteractions(mockSessionExpirationListener)
|
verifyNoInteractions(mockSessionExpirationListener)
|
||||||
```
|
```
|
||||||
|
|
||||||
Now we just need to declare our parameters for our test:
|
Now we just need to declare our parameters for our test:
|
||||||
|
|
@ -247,7 +247,7 @@ fun networkInputError(authScenario: AuthScenario) = runTest {
|
||||||
Assertions.assertTrue(answer is Answer.Error, "Answer is expected to be an Error")
|
Assertions.assertTrue(answer is Answer.Error, "Answer is expected to be an Error")
|
||||||
Assertions.assertFalse(actual, "User is expected to be not logged in")
|
Assertions.assertFalse(actual, "User is expected to be not logged in")
|
||||||
Assertions.assertEquals(null, fakeUserDataLocalStorage.session)
|
Assertions.assertEquals(null, fakeUserDataLocalStorage.session)
|
||||||
verifyZeroInteractions(mockSessionExpirationListener)
|
verifyNoInteractions(mockSessionExpirationListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
//...
|
//...
|
||||||
|
|
@ -282,7 +282,7 @@ fun loginInvalidCredentials() = runTest {
|
||||||
Assertions.assertEquals(Answer.Success(LoginStatus.INVALID_CREDENTIALS), answer)
|
Assertions.assertEquals(Answer.Success(LoginStatus.INVALID_CREDENTIALS), answer)
|
||||||
Assertions.assertFalse(actual, "User is expected to be not logged in")
|
Assertions.assertFalse(actual, "User is expected to be not logged in")
|
||||||
Assertions.assertEquals(null, fakeUserDataLocalStorage.session)
|
Assertions.assertEquals(null, fakeUserDataLocalStorage.session)
|
||||||
verifyZeroInteractions(mockSessionExpirationListener)
|
verifyNoInteractions(mockSessionExpirationListener)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -305,7 +305,7 @@ And we verify the user is indeed logged out now:
|
||||||
```kotlin
|
```kotlin
|
||||||
Assertions.assertFalse(actual, "User is expected to be logged out")
|
Assertions.assertFalse(actual, "User is expected to be logged out")
|
||||||
Assertions.assertEquals(null, fakeUserDataLocalStorage.session)
|
Assertions.assertEquals(null, fakeUserDataLocalStorage.session)
|
||||||
verifyZeroInteractions(mockSessionExpirationListener)
|
verifyNoInteractions(mockSessionExpirationListener)
|
||||||
```
|
```
|
||||||
|
|
||||||
### 7. `logoutReleasesContent`
|
### 7. `logoutReleasesContent`
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ When the class is created, the delegate should not yet be touched, so we start t
|
||||||
@DisplayName("WHEN nothing is changed THEN delegate is not touched") // this will show up when running our tests and is a great way to document what we are testing
|
@DisplayName("WHEN nothing is changed THEN delegate is not touched") // this will show up when running our tests and is a great way to document what we are testing
|
||||||
@Test // this defines that this method is a test, needs to be org.junit.jupiter.api.Test
|
@Test // this defines that this method is a test, needs to be org.junit.jupiter.api.Test
|
||||||
fun verifyNoInteractionsIfNoInvocations() {
|
fun verifyNoInteractionsIfNoInvocations() {
|
||||||
verifyZeroInteractions(mockSessionExpirationListener) // we verify that our mock object's functions / properties have not been touched
|
verifyNoInteractions(mockSessionExpirationListener) // we verify that our mock object's functions / properties have not been touched
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -131,8 +131,8 @@ Lastly we add verification:
|
||||||
|
|
||||||
```kotlin
|
```kotlin
|
||||||
Assertions.assertEquals(expected, actual) // assert the result is what we expected
|
Assertions.assertEquals(expected, actual) // assert the result is what we expected
|
||||||
verifyZeroInteractions(mockLoginRemoteSource) // assert no request was called
|
verifyNoInteractions(mockLoginRemoteSource) // assert no request was called
|
||||||
verifyZeroInteractions(mockUserDataLocalStorage) // assert we didn't modify our storage
|
verifyNoInteractions(mockUserDataLocalStorage) // assert we didn't modify our storage
|
||||||
```
|
```
|
||||||
|
|
||||||
But something is wrong, the invoke method cannot be executed since it's a suspending function.
|
But something is wrong, the invoke method cannot be executed since it's a suspending function.
|
||||||
|
|
@ -148,8 +148,8 @@ fun emptyUserNameReturnsLoginStatusError() = runTest {
|
||||||
val actual = sut.invoke(LoginCredentials("", "a"))
|
val actual = sut.invoke(LoginCredentials("", "a"))
|
||||||
|
|
||||||
Assertions.assertEquals(expected, actual)
|
Assertions.assertEquals(expected, actual)
|
||||||
verifyZeroInteractions(mockLoginRemoteSource)
|
verifyNoInteractions(mockLoginRemoteSource)
|
||||||
verifyZeroInteractions(mockUserDataLocalStorage)
|
verifyNoInteractions(mockUserDataLocalStorage)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -172,8 +172,8 @@ fun emptyPasswordNameReturnsLoginStatusError() = runTest {
|
||||||
val actual = sut.invoke(LoginCredentials("a", ""))
|
val actual = sut.invoke(LoginCredentials("a", ""))
|
||||||
|
|
||||||
Assertions.assertEquals(expected, actual)
|
Assertions.assertEquals(expected, actual)
|
||||||
verifyZeroInteractions(mockLoginRemoteSource)
|
verifyNoInteractions(mockLoginRemoteSource)
|
||||||
verifyZeroInteractions(mockUserDataLocalStorage)
|
verifyNoInteractions(mockUserDataLocalStorage)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -211,7 +211,7 @@ And finally verification:
|
||||||
|
|
||||||
```kotlin
|
```kotlin
|
||||||
Assertions.assertEquals(expected, actual)
|
Assertions.assertEquals(expected, actual)
|
||||||
verifyZeroInteractions(mockUserDataLocalStorage)
|
verifyNoInteractions(mockUserDataLocalStorage)
|
||||||
```
|
```
|
||||||
|
|
||||||
Together:
|
Together:
|
||||||
|
|
@ -226,7 +226,7 @@ fun invalidLoginResponseReturnInvalidCredentials() = runTest {
|
||||||
val actual = sut.invoke(LoginCredentials("a", "b"))
|
val actual = sut.invoke(LoginCredentials("a", "b"))
|
||||||
|
|
||||||
Assertions.assertEquals(expected, actual)
|
Assertions.assertEquals(expected, actual)
|
||||||
verifyZeroInteractions(mockUserDataLocalStorage)
|
verifyNoInteractions(mockUserDataLocalStorage)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -291,7 +291,7 @@ Verification:
|
||||||
|
|
||||||
```kotlin
|
```kotlin
|
||||||
Assertions.assertEquals(expected, actual)
|
Assertions.assertEquals(expected, actual)
|
||||||
verifyZeroInteractions(mockUserDataLocalStorage)
|
verifyNoInteractions(mockUserDataLocalStorage)
|
||||||
```
|
```
|
||||||
|
|
||||||
Together:
|
Together:
|
||||||
|
|
@ -308,7 +308,7 @@ fun invalidResponseResultsInErrorReturned() = runTest {
|
||||||
val actual = sut.invoke(LoginCredentials("a", "b"))
|
val actual = sut.invoke(LoginCredentials("a", "b"))
|
||||||
|
|
||||||
Assertions.assertEquals(expected, actual)
|
Assertions.assertEquals(expected, actual)
|
||||||
verifyZeroInteractions(mockUserDataLocalStorage)
|
verifyNoInteractions(mockUserDataLocalStorage)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
#### Lessons learned
|
#### Lessons learned
|
||||||
|
|
|
||||||
|
|
@ -328,7 +328,7 @@ Assertions.assertEquals("login-access", contentRequestAfterRefreshed.getHeader("
|
||||||
// this matches the data from the success_response_login.json
|
// this matches the data from the success_response_login.json
|
||||||
val expectedSavedSession = Session(accessToken = "login-access", refreshToken = "login-refresh")
|
val expectedSavedSession = Session(accessToken = "login-access", refreshToken = "login-refresh")
|
||||||
verify(mockNetworkSessionLocalStorage, times(1)).session = expectedSavedSession
|
verify(mockNetworkSessionLocalStorage, times(1)).session = expectedSavedSession
|
||||||
verifyZeroInteractions(mockNetworkSessionExpirationListener)
|
verifyNoInteractions(mockNetworkSessionExpirationListener)
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. `failingRefreshResultsInSessionExpiration`
|
### 2. `failingRefreshResultsInSessionExpiration`
|
||||||
|
|
|
||||||
|
|
@ -186,7 +186,7 @@ class CodeKataFavouriteContentLocalStorage: KoinTest
|
||||||
- we add a testDispatcher to Room
|
- we add a testDispatcher to Room
|
||||||
- we switch to runTest(testDispatcher)
|
- we switch to runTest(testDispatcher)
|
||||||
|
|
||||||
Since Room has their own exercutors, that could make our tests flaky, since it might get out of sync. Luckily we can switch out these executors, so we do that to make sure our tests run just as we would like them to.
|
Since Room has their own executors, that could make our tests flaky, since it might get out of sync. Luckily we can switch out these executors, so we do that to make sure our tests run just as we would like them to.
|
||||||
|
|
||||||
```
|
```
|
||||||
private val sut by inject<FavouriteContentLocalStorage>()
|
private val sut by inject<FavouriteContentLocalStorage>()
|
||||||
|
|
@ -195,7 +195,7 @@ private lateinit var testDispatcher: TestDispatcher
|
||||||
@Before
|
@Before
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
testDispatcher = StandardTestDispatcher()
|
testDispatcher = StandardTestDispatcher()
|
||||||
DatabaseInitialization.dispatcher = testDispatcher
|
TestDatabaseInitialization.overwriteDatabaseInitialization(testDispatcher)
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
|
|
@ -204,15 +204,16 @@ fun tearDown() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun atTheStartOurDatabaseIsEmpty()= runTest(testDispatcher) {
|
fun atTheStartOurDatabaseIsEmpty() = runTest(testDispatcher) {
|
||||||
sut.observeFavourites().first()
|
sut.observeFavourites().first()
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The line `DatabaseInitialization.dispatcher = testDispatcher` may look a bit mysterious, but all we do with it is to overwrite our original DatabaseInitialization in tests, and use the given Dispatcher as an executor for Room setup.
|
The line `TestDatabaseInitialization.overwriteDatabaseInitialization(testDispatcher)` may look a bit mysterious, but all we do with it is overwrite the koin module to use our an InMemoryDatabase in our tests with the Dispatcher used as executor.
|
||||||
|
|
||||||
> DatabaseInitialization is overwritten in the Test module, by declaring the same class in the same package with the same methods. This is an easy way to switch out an implementation.
|
> Above min API 24
|
||||||
> This might not look the cleanest, so an alternative way is to switch out the koin-module of how to create the database. For this we could use loadKoinModules. In other dependency injection / service locator frameworks this should also be possible.
|
> DatabaseInitialization could be overwritten in Test module, by declaring the same class in the same package with the same methods. This is an easy way to switch out an implementation.
|
||||||
|
> That might not look the cleanest, so an the presented way of switch out the koin-module creating the database is preferred. In other dependency injection / service locator frameworks this should also be possible.
|
||||||
|
|
||||||
### 1. `atTheStartOurDatabaseIsEmpty`
|
### 1. `atTheStartOurDatabaseIsEmpty`
|
||||||
|
|
||||||
|
|
@ -518,7 +519,7 @@ fun tearDown() {
|
||||||
```
|
```
|
||||||
|
|
||||||
> Idling Resources comes from Espresso. The idea is that anytime we want to interact with the UI via Espresso, it will await any Idling Resource beforehand. This is handy, since our Network component, (OkHttp) uses it's own thread pool, and we would like to have a way to await the responses.
|
> Idling Resources comes from Espresso. The idea is that anytime we want to interact with the UI via Espresso, it will await any Idling Resource beforehand. This is handy, since our Network component, (OkHttp) uses it's own thread pool, and we would like to have a way to await the responses.
|
||||||
> Disposable is just a syntetic-sugar way to remove the OkHttpIdling resource from Espresso when we no longer need it.
|
> Disposable is just a synthetic-sugar way to remove the OkHttpIdling resource from Espresso when we no longer need it.
|
||||||
> Idling Resources also makes it easy for us, to coordinate coroutines with our network responses, since we can await the IdlingResource and advance the Coroutines afterwards.
|
> Idling Resources also makes it easy for us, to coordinate coroutines with our network responses, since we can await the IdlingResource and advance the Coroutines afterwards.
|
||||||
|
|
||||||
##### Coroutine Test Setup
|
##### Coroutine Test Setup
|
||||||
|
|
@ -531,7 +532,7 @@ fun setup() {
|
||||||
val dispatcher = StandardTestDispatcher()
|
val dispatcher = StandardTestDispatcher()
|
||||||
Dispatchers.setMain(dispatcher)
|
Dispatchers.setMain(dispatcher)
|
||||||
testDispatcher = dispatcher
|
testDispatcher = dispatcher
|
||||||
DatabaseInitialization.dispatcher = dispatcher
|
TestDatabaseInitialization.overwriteDatabaseInitialization(testDispatcher)
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
|
|
|
||||||
|
|
@ -129,10 +129,10 @@ So that's because something went wrong in our first test. I am describing these
|
||||||
|
|
||||||
Now, here is a new difference between Robolectric and AndroidTest. In Robolectric, before every test, the Application class is initialized, however in AndroidTests, the Application class is only initialized once.
|
Now, here is a new difference between Robolectric and AndroidTest. In Robolectric, before every test, the Application class is initialized, however in AndroidTests, the Application class is only initialized once.
|
||||||
This is great if you want to have End-to-End tests that follow each other, but since now we only want to tests some small subsection of the functionality, we have to restart Koin before every tests if it isn't yet started so our tests don't use the same instances.
|
This is great if you want to have End-to-End tests that follow each other, but since now we only want to tests some small subsection of the functionality, we have to restart Koin before every tests if it isn't yet started so our tests don't use the same instances.
|
||||||
We will check if koin is initalized, if it isn't then we simply initalize it:
|
We will check if koin is initialized, if it isn't then we simply initialize it:
|
||||||
```kotlin
|
```kotlin
|
||||||
...
|
...
|
||||||
DatabaseInitialization.dispatcher = dispatcher
|
TestDatabaseInitialization.overwriteDatabaseInitialization(dispatcher)
|
||||||
if (GlobalContext.getOrNull() == null) {
|
if (GlobalContext.getOrNull() == null) {
|
||||||
val application = ApplicationProvider.getApplicationContext<TestShowcaseApplication>()
|
val application = ApplicationProvider.getApplicationContext<TestShowcaseApplication>()
|
||||||
val baseUrl = BaseUrl(BuildConfig.BASE_URL)
|
val baseUrl = BaseUrl(BuildConfig.BASE_URL)
|
||||||
|
|
@ -237,7 +237,7 @@ Let's create a TestRule for that setup next.
|
||||||
val dispatcher = StandardTestDispatcher()
|
val dispatcher = StandardTestDispatcher()
|
||||||
Dispatchers.setMain(dispatcher)
|
Dispatchers.setMain(dispatcher)
|
||||||
testDispatcher = dispatcher
|
testDispatcher = dispatcher
|
||||||
DatabaseInitialization.dispatcher = dispatcher
|
TestDatabaseInitialization.overwriteDatabaseInitialization(dispatcher)
|
||||||
|
|
||||||
// after
|
// after
|
||||||
Dispatchers.resetMain()
|
Dispatchers.resetMain()
|
||||||
|
|
@ -253,7 +253,7 @@ override fun apply(base: Statement, description: Description): Statement = objec
|
||||||
try {
|
try {
|
||||||
val dispatcher = StandardTestDispatcher()
|
val dispatcher = StandardTestDispatcher()
|
||||||
Dispatchers.setMain(dispatcher)
|
Dispatchers.setMain(dispatcher)
|
||||||
DatabaseInitialization.dispatcher = dispatcher
|
TestDatabaseInitialization.overwriteDatabaseInitialization(dispatcher)
|
||||||
_testDispatcher = dispatcher
|
_testDispatcher = dispatcher
|
||||||
base.evaluate()
|
base.evaluate()
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,8 @@ import org.mockito.kotlin.doThrow
|
||||||
import org.mockito.kotlin.mock
|
import org.mockito.kotlin.mock
|
||||||
import org.mockito.kotlin.times
|
import org.mockito.kotlin.times
|
||||||
import org.mockito.kotlin.verify
|
import org.mockito.kotlin.verify
|
||||||
|
import org.mockito.kotlin.verifyNoInteractions
|
||||||
import org.mockito.kotlin.verifyNoMoreInteractions
|
import org.mockito.kotlin.verifyNoMoreInteractions
|
||||||
import org.mockito.kotlin.verifyZeroInteractions
|
|
||||||
import org.mockito.kotlin.whenever
|
import org.mockito.kotlin.whenever
|
||||||
|
|
||||||
@Suppress("TestFunctionName")
|
@Suppress("TestFunctionName")
|
||||||
|
|
@ -33,7 +33,7 @@ internal class AddContentToFavouriteUseCaseTest {
|
||||||
@DisplayName("WHEN nothing happens THEN the storage is not touched")
|
@DisplayName("WHEN nothing happens THEN the storage is not touched")
|
||||||
@Test
|
@Test
|
||||||
fun initializationDoesntAffectStorage() {
|
fun initializationDoesntAffectStorage() {
|
||||||
verifyZeroInteractions(mockFavouriteContentLocalStorage)
|
verifyNoInteractions(mockFavouriteContentLocalStorage)
|
||||||
}
|
}
|
||||||
|
|
||||||
@DisplayName("GIVEN contentId WHEN called THEN storage is called")
|
@DisplayName("GIVEN contentId WHEN called THEN storage is called")
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@ import org.mockito.kotlin.doThrow
|
||||||
import org.mockito.kotlin.mock
|
import org.mockito.kotlin.mock
|
||||||
import org.mockito.kotlin.times
|
import org.mockito.kotlin.times
|
||||||
import org.mockito.kotlin.verify
|
import org.mockito.kotlin.verify
|
||||||
|
import org.mockito.kotlin.verifyNoInteractions
|
||||||
import org.mockito.kotlin.verifyNoMoreInteractions
|
import org.mockito.kotlin.verifyNoMoreInteractions
|
||||||
import org.mockito.kotlin.verifyZeroInteractions
|
|
||||||
import org.mockito.kotlin.whenever
|
import org.mockito.kotlin.whenever
|
||||||
|
|
||||||
@Suppress("TestFunctionName")
|
@Suppress("TestFunctionName")
|
||||||
|
|
@ -31,7 +31,7 @@ internal class FetchContentUseCaseTest {
|
||||||
@DisplayName("WHEN nothing happens THEN the storage is not touched")
|
@DisplayName("WHEN nothing happens THEN the storage is not touched")
|
||||||
@Test
|
@Test
|
||||||
fun initializationDoesntAffectRepository() {
|
fun initializationDoesntAffectRepository() {
|
||||||
verifyZeroInteractions(mockContentRepository)
|
verifyNoInteractions(mockContentRepository)
|
||||||
}
|
}
|
||||||
|
|
||||||
@DisplayName("WHEN called THEN repository is called")
|
@DisplayName("WHEN called THEN repository is called")
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,8 @@ import org.mockito.kotlin.doThrow
|
||||||
import org.mockito.kotlin.mock
|
import org.mockito.kotlin.mock
|
||||||
import org.mockito.kotlin.times
|
import org.mockito.kotlin.times
|
||||||
import org.mockito.kotlin.verify
|
import org.mockito.kotlin.verify
|
||||||
|
import org.mockito.kotlin.verifyNoInteractions
|
||||||
import org.mockito.kotlin.verifyNoMoreInteractions
|
import org.mockito.kotlin.verifyNoMoreInteractions
|
||||||
import org.mockito.kotlin.verifyZeroInteractions
|
|
||||||
import org.mockito.kotlin.whenever
|
import org.mockito.kotlin.whenever
|
||||||
|
|
||||||
@Suppress("TestFunctionName")
|
@Suppress("TestFunctionName")
|
||||||
|
|
@ -33,7 +33,7 @@ internal class RemoveContentFromFavouritesUseCaseTest {
|
||||||
@DisplayName("WHEN nothing happens THEN the storage is not touched")
|
@DisplayName("WHEN nothing happens THEN the storage is not touched")
|
||||||
@Test
|
@Test
|
||||||
fun initializationDoesntAffectStorage() {
|
fun initializationDoesntAffectStorage() {
|
||||||
verifyZeroInteractions(mockFavouriteContentLocalStorage)
|
verifyNoInteractions(mockFavouriteContentLocalStorage)
|
||||||
}
|
}
|
||||||
|
|
||||||
@DisplayName("GIVEN contentId WHEN called THEN storage is called")
|
@DisplayName("GIVEN contentId WHEN called THEN storage is called")
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ import org.koin.test.KoinTest
|
||||||
import org.koin.test.get
|
import org.koin.test.get
|
||||||
import org.koin.test.inject
|
import org.koin.test.inject
|
||||||
import org.mockito.kotlin.mock
|
import org.mockito.kotlin.mock
|
||||||
import org.mockito.kotlin.verifyZeroInteractions
|
import org.mockito.kotlin.verifyNoInteractions
|
||||||
import java.util.stream.Stream
|
import java.util.stream.Stream
|
||||||
|
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
|
@ -86,7 +86,7 @@ class AuthIntegrationTest : KoinTest {
|
||||||
val actual = isUserLoggedInUseCase.invoke()
|
val actual = isUserLoggedInUseCase.invoke()
|
||||||
|
|
||||||
Assertions.assertFalse(actual, "User is expected to be not logged in")
|
Assertions.assertFalse(actual, "User is expected to be not logged in")
|
||||||
verifyZeroInteractions(mockSessionExpirationListener)
|
verifyNoInteractions(mockSessionExpirationListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
@DisplayName("GIVEN no session WHEN user is logging in THEN they get session")
|
@DisplayName("GIVEN no session WHEN user is logging in THEN they get session")
|
||||||
|
|
@ -101,7 +101,7 @@ class AuthIntegrationTest : KoinTest {
|
||||||
Assertions.assertEquals(Answer.Success(LoginStatus.SUCCESS), answer)
|
Assertions.assertEquals(Answer.Success(LoginStatus.SUCCESS), answer)
|
||||||
Assertions.assertTrue(actual, "User is expected to be logged in")
|
Assertions.assertTrue(actual, "User is expected to be logged in")
|
||||||
Assertions.assertEquals(expectedSession, fakeUserDataLocalStorage.session)
|
Assertions.assertEquals(expectedSession, fakeUserDataLocalStorage.session)
|
||||||
verifyZeroInteractions(mockSessionExpirationListener)
|
verifyNoInteractions(mockSessionExpirationListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
@MethodSource("localInputErrorArguments")
|
@MethodSource("localInputErrorArguments")
|
||||||
|
|
@ -113,7 +113,7 @@ class AuthIntegrationTest : KoinTest {
|
||||||
Assertions.assertEquals(Answer.Success(loginError), answer)
|
Assertions.assertEquals(Answer.Success(loginError), answer)
|
||||||
Assertions.assertFalse(actual, "User is expected to be not logged in")
|
Assertions.assertFalse(actual, "User is expected to be not logged in")
|
||||||
Assertions.assertEquals(null, fakeUserDataLocalStorage.session)
|
Assertions.assertEquals(null, fakeUserDataLocalStorage.session)
|
||||||
verifyZeroInteractions(mockSessionExpirationListener)
|
verifyNoInteractions(mockSessionExpirationListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
@MethodSource("networkErrorArguments")
|
@MethodSource("networkErrorArguments")
|
||||||
|
|
@ -127,7 +127,7 @@ class AuthIntegrationTest : KoinTest {
|
||||||
Assertions.assertTrue(answer is Answer.Error, "Answer is expected to be an Error")
|
Assertions.assertTrue(answer is Answer.Error, "Answer is expected to be an Error")
|
||||||
Assertions.assertFalse(actual, "User is expected to be not logged in")
|
Assertions.assertFalse(actual, "User is expected to be not logged in")
|
||||||
Assertions.assertEquals(null, fakeUserDataLocalStorage.session)
|
Assertions.assertEquals(null, fakeUserDataLocalStorage.session)
|
||||||
verifyZeroInteractions(mockSessionExpirationListener)
|
verifyNoInteractions(mockSessionExpirationListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
@DisplayName("GIVEN invalid credentials response WHEN user is logging in THEN they get proper error")
|
@DisplayName("GIVEN invalid credentials response WHEN user is logging in THEN they get proper error")
|
||||||
|
|
@ -141,7 +141,7 @@ class AuthIntegrationTest : KoinTest {
|
||||||
Assertions.assertEquals(Answer.Success(LoginStatus.INVALID_CREDENTIALS), answer)
|
Assertions.assertEquals(Answer.Success(LoginStatus.INVALID_CREDENTIALS), answer)
|
||||||
Assertions.assertFalse(actual, "User is expected to be not logged in")
|
Assertions.assertFalse(actual, "User is expected to be not logged in")
|
||||||
Assertions.assertEquals(null, fakeUserDataLocalStorage.session)
|
Assertions.assertEquals(null, fakeUserDataLocalStorage.session)
|
||||||
verifyZeroInteractions(mockSessionExpirationListener)
|
verifyNoInteractions(mockSessionExpirationListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
@DisplayName("GIVEN logged in user WHEN user is logging out THEN they no longer have a session")
|
@DisplayName("GIVEN logged in user WHEN user is logging out THEN they no longer have a session")
|
||||||
|
|
@ -155,7 +155,7 @@ class AuthIntegrationTest : KoinTest {
|
||||||
|
|
||||||
Assertions.assertFalse(actual, "User is expected to be logged out")
|
Assertions.assertFalse(actual, "User is expected to be logged out")
|
||||||
Assertions.assertEquals(null, fakeUserDataLocalStorage.session)
|
Assertions.assertEquals(null, fakeUserDataLocalStorage.session)
|
||||||
verifyZeroInteractions(mockSessionExpirationListener)
|
verifyNoInteractions(mockSessionExpirationListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
@DisplayName("GIVEN logged in user WHEN user is logging out THEN content is cleared")
|
@DisplayName("GIVEN logged in user WHEN user is logging out THEN content is cleared")
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ import org.koin.core.context.stopKoin
|
||||||
import org.koin.test.KoinTest
|
import org.koin.test.KoinTest
|
||||||
import org.koin.test.inject
|
import org.koin.test.inject
|
||||||
import org.mockito.kotlin.mock
|
import org.mockito.kotlin.mock
|
||||||
import org.mockito.kotlin.verifyZeroInteractions
|
import org.mockito.kotlin.verifyNoInteractions
|
||||||
|
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
class ContentIntegrationTest : KoinTest {
|
class ContentIntegrationTest : KoinTest {
|
||||||
|
|
@ -97,7 +97,7 @@ class ContentIntegrationTest : KoinTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
Assertions.assertEquals(expected, actual.await())
|
Assertions.assertEquals(expected, actual.await())
|
||||||
verifyZeroInteractions(mockSessionExpirationListener)
|
verifyNoInteractions(mockSessionExpirationListener)
|
||||||
Assertions.assertSame(session, fakeUserDataLocalStorage.session)
|
Assertions.assertSame(session, fakeUserDataLocalStorage.session)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -120,7 +120,7 @@ class ContentIntegrationTest : KoinTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
Assertions.assertEquals(expected, actual.await())
|
Assertions.assertEquals(expected, actual.await())
|
||||||
verifyZeroInteractions(mockSessionExpirationListener)
|
verifyNoInteractions(mockSessionExpirationListener)
|
||||||
Assertions.assertSame(session, fakeUserDataLocalStorage.session)
|
Assertions.assertSame(session, fakeUserDataLocalStorage.session)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -150,7 +150,7 @@ class ContentIntegrationTest : KoinTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
Assertions.assertEquals(expected, actual.await())
|
Assertions.assertEquals(expected, actual.await())
|
||||||
verifyZeroInteractions(mockSessionExpirationListener)
|
verifyNoInteractions(mockSessionExpirationListener)
|
||||||
Assertions.assertSame(session, fakeUserDataLocalStorage.session)
|
Assertions.assertSame(session, fakeUserDataLocalStorage.session)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -201,7 +201,7 @@ class ContentIntegrationTest : KoinTest {
|
||||||
|
|
||||||
Assertions.assertIterableEquals(expected, actual.await())
|
Assertions.assertIterableEquals(expected, actual.await())
|
||||||
Assertions.assertEquals(expected.last(), verifyCaching.await())
|
Assertions.assertEquals(expected.last(), verifyCaching.await())
|
||||||
verifyZeroInteractions(mockSessionExpirationListener)
|
verifyNoInteractions(mockSessionExpirationListener)
|
||||||
Assertions.assertSame(session, fakeUserDataLocalStorage.session)
|
Assertions.assertSame(session, fakeUserDataLocalStorage.session)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -229,7 +229,7 @@ class ContentIntegrationTest : KoinTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
Assertions.assertIterableEquals(expected, actual.await())
|
Assertions.assertIterableEquals(expected, actual.await())
|
||||||
verifyZeroInteractions(mockSessionExpirationListener)
|
verifyNoInteractions(mockSessionExpirationListener)
|
||||||
Assertions.assertSame(session, fakeUserDataLocalStorage.session)
|
Assertions.assertSame(session, fakeUserDataLocalStorage.session)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -268,7 +268,7 @@ class ContentIntegrationTest : KoinTest {
|
||||||
Assertions.assertTrue((actualValues[1] as Resource.Error).error is NetworkException, "Resource is Network Error")
|
Assertions.assertTrue((actualValues[1] as Resource.Error).error is NetworkException, "Resource is Network Error")
|
||||||
Assertions.assertEquals(expected[2], actualValues[2])
|
Assertions.assertEquals(expected[2], actualValues[2])
|
||||||
Assertions.assertEquals(expected[3], actualValues[3])
|
Assertions.assertEquals(expected[3], actualValues[3])
|
||||||
verifyZeroInteractions(mockSessionExpirationListener)
|
verifyNoInteractions(mockSessionExpirationListener)
|
||||||
Assertions.assertSame(session, fakeUserDataLocalStorage.session)
|
Assertions.assertSame(session, fakeUserDataLocalStorage.session)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -331,7 +331,7 @@ class ContentIntegrationTest : KoinTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
Assertions.assertIterableEquals(expected, actual.await())
|
Assertions.assertIterableEquals(expected, actual.await())
|
||||||
verifyZeroInteractions(mockSessionExpirationListener)
|
verifyNoInteractions(mockSessionExpirationListener)
|
||||||
val expectedSession = Session(accessToken = "refreshed-access", refreshToken = "refreshed-refresh")
|
val expectedSession = Session(accessToken = "refreshed-access", refreshToken = "refreshed-refresh")
|
||||||
Assertions.assertEquals(expectedSession, fakeUserDataLocalStorage.session)
|
Assertions.assertEquals(expectedSession, fakeUserDataLocalStorage.session)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,8 +34,8 @@ import org.koin.test.inject
|
||||||
import org.mockito.kotlin.mock
|
import org.mockito.kotlin.mock
|
||||||
import org.mockito.kotlin.times
|
import org.mockito.kotlin.times
|
||||||
import org.mockito.kotlin.verify
|
import org.mockito.kotlin.verify
|
||||||
|
import org.mockito.kotlin.verifyNoInteractions
|
||||||
import org.mockito.kotlin.verifyNoMoreInteractions
|
import org.mockito.kotlin.verifyNoMoreInteractions
|
||||||
import org.mockito.kotlin.verifyZeroInteractions
|
|
||||||
|
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
class SessionExpirationIntegrationTest : KoinTest {
|
class SessionExpirationIntegrationTest : KoinTest {
|
||||||
|
|
@ -82,7 +82,7 @@ class SessionExpirationIntegrationTest : KoinTest {
|
||||||
mockServerScenarioSetup.setScenario(AuthScenario.Success(username = "a", password = "b"), validateArguments = true)
|
mockServerScenarioSetup.setScenario(AuthScenario.Success(username = "a", password = "b"), validateArguments = true)
|
||||||
loginUseCase.invoke(LoginCredentials(username = "a", password = "b"))
|
loginUseCase.invoke(LoginCredentials(username = "a", password = "b"))
|
||||||
Assertions.assertTrue(isUserLoggedInUseCase.invoke())
|
Assertions.assertTrue(isUserLoggedInUseCase.invoke())
|
||||||
verifyZeroInteractions(mockSessionExpirationListener)
|
verifyNoInteractions(mockSessionExpirationListener)
|
||||||
|
|
||||||
mockServerScenarioSetup.setScenario(ContentScenario.Unauthorized(usingRefreshedToken = false))
|
mockServerScenarioSetup.setScenario(ContentScenario.Unauthorized(usingRefreshedToken = false))
|
||||||
.setScenario(RefreshTokenScenario.Error)
|
.setScenario(RefreshTokenScenario.Error)
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import org.junit.jupiter.api.DisplayName
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import org.mockito.kotlin.doReturn
|
import org.mockito.kotlin.doReturn
|
||||||
import org.mockito.kotlin.mock
|
import org.mockito.kotlin.mock
|
||||||
import org.mockito.kotlin.verifyZeroInteractions
|
import org.mockito.kotlin.verifyNoInteractions
|
||||||
import org.mockito.kotlin.whenever
|
import org.mockito.kotlin.whenever
|
||||||
|
|
||||||
@Suppress("TestFunctionName")
|
@Suppress("TestFunctionName")
|
||||||
|
|
@ -26,7 +26,7 @@ internal class IsUserLoggedInUseCaseTest {
|
||||||
@DisplayName("WHEN nothing is called THEN storage is not called")
|
@DisplayName("WHEN nothing is called THEN storage is not called")
|
||||||
@Test
|
@Test
|
||||||
fun creatingDoesntAffectStorage() {
|
fun creatingDoesntAffectStorage() {
|
||||||
verifyZeroInteractions(mockUserDataLocalStorage)
|
verifyNoInteractions(mockUserDataLocalStorage)
|
||||||
}
|
}
|
||||||
|
|
||||||
@DisplayName("GIVEN session data saved WHEN is user logged in checked THEN true is returned")
|
@DisplayName("GIVEN session data saved WHEN is user logged in checked THEN true is returned")
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,8 @@ import org.mockito.kotlin.doThrow
|
||||||
import org.mockito.kotlin.mock
|
import org.mockito.kotlin.mock
|
||||||
import org.mockito.kotlin.times
|
import org.mockito.kotlin.times
|
||||||
import org.mockito.kotlin.verify
|
import org.mockito.kotlin.verify
|
||||||
|
import org.mockito.kotlin.verifyNoInteractions
|
||||||
import org.mockito.kotlin.verifyNoMoreInteractions
|
import org.mockito.kotlin.verifyNoMoreInteractions
|
||||||
import org.mockito.kotlin.verifyZeroInteractions
|
|
||||||
import org.mockito.kotlin.whenever
|
import org.mockito.kotlin.whenever
|
||||||
|
|
||||||
@Suppress("TestFunctionName")
|
@Suppress("TestFunctionName")
|
||||||
|
|
@ -46,8 +46,8 @@ internal class LoginUseCaseTest {
|
||||||
val actual = sut.invoke(LoginCredentials("", "a"))
|
val actual = sut.invoke(LoginCredentials("", "a"))
|
||||||
|
|
||||||
Assertions.assertEquals(expected, actual)
|
Assertions.assertEquals(expected, actual)
|
||||||
verifyZeroInteractions(mockLoginRemoteSource)
|
verifyNoInteractions(mockLoginRemoteSource)
|
||||||
verifyZeroInteractions(mockUserDataLocalStorage)
|
verifyNoInteractions(mockUserDataLocalStorage)
|
||||||
}
|
}
|
||||||
|
|
||||||
@DisplayName("GIVEN empty password WHEN trying to login THEN invalid password is returned")
|
@DisplayName("GIVEN empty password WHEN trying to login THEN invalid password is returned")
|
||||||
|
|
@ -58,8 +58,8 @@ internal class LoginUseCaseTest {
|
||||||
val actual = sut.invoke(LoginCredentials("a", ""))
|
val actual = sut.invoke(LoginCredentials("a", ""))
|
||||||
|
|
||||||
Assertions.assertEquals(expected, actual)
|
Assertions.assertEquals(expected, actual)
|
||||||
verifyZeroInteractions(mockLoginRemoteSource)
|
verifyNoInteractions(mockLoginRemoteSource)
|
||||||
verifyZeroInteractions(mockUserDataLocalStorage)
|
verifyNoInteractions(mockUserDataLocalStorage)
|
||||||
}
|
}
|
||||||
|
|
||||||
@DisplayName("GIVEN invalid credentials response WHEN trying to login THEN invalid credentials is returned ")
|
@DisplayName("GIVEN invalid credentials response WHEN trying to login THEN invalid credentials is returned ")
|
||||||
|
|
@ -72,7 +72,7 @@ internal class LoginUseCaseTest {
|
||||||
val actual = sut.invoke(LoginCredentials("a", "b"))
|
val actual = sut.invoke(LoginCredentials("a", "b"))
|
||||||
|
|
||||||
Assertions.assertEquals(expected, actual)
|
Assertions.assertEquals(expected, actual)
|
||||||
verifyZeroInteractions(mockUserDataLocalStorage)
|
verifyNoInteractions(mockUserDataLocalStorage)
|
||||||
}
|
}
|
||||||
|
|
||||||
@DisplayName("GIVEN success response WHEN trying to login THEN session is saved and success is returned")
|
@DisplayName("GIVEN success response WHEN trying to login THEN session is saved and success is returned")
|
||||||
|
|
@ -100,6 +100,6 @@ internal class LoginUseCaseTest {
|
||||||
val actual = sut.invoke(LoginCredentials("a", "b"))
|
val actual = sut.invoke(LoginCredentials("a", "b"))
|
||||||
|
|
||||||
Assertions.assertEquals(expected, actual)
|
Assertions.assertEquals(expected, actual)
|
||||||
verifyZeroInteractions(mockUserDataLocalStorage)
|
verifyNoInteractions(mockUserDataLocalStorage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,8 @@ import org.koin.test.KoinTest
|
||||||
import org.mockito.kotlin.mock
|
import org.mockito.kotlin.mock
|
||||||
import org.mockito.kotlin.times
|
import org.mockito.kotlin.times
|
||||||
import org.mockito.kotlin.verify
|
import org.mockito.kotlin.verify
|
||||||
|
import org.mockito.kotlin.verifyNoInteractions
|
||||||
import org.mockito.kotlin.verifyNoMoreInteractions
|
import org.mockito.kotlin.verifyNoMoreInteractions
|
||||||
import org.mockito.kotlin.verifyZeroInteractions
|
|
||||||
|
|
||||||
@Suppress("TestFunctionName")
|
@Suppress("TestFunctionName")
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
|
@ -52,7 +52,7 @@ internal class LogoutUseCaseTest : KoinTest {
|
||||||
@DisplayName("WHEN no call THEN storage is not interacted")
|
@DisplayName("WHEN no call THEN storage is not interacted")
|
||||||
@Test
|
@Test
|
||||||
fun initializedDoesntAffectStorage() {
|
fun initializedDoesntAffectStorage() {
|
||||||
verifyZeroInteractions(mockUserDataLocalStorage)
|
verifyNoInteractions(mockUserDataLocalStorage)
|
||||||
}
|
}
|
||||||
|
|
||||||
@DisplayName("WHEN logout invoked THEN storage is cleared")
|
@DisplayName("WHEN logout invoked THEN storage is cleared")
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ import org.junit.jupiter.api.Test
|
||||||
import org.mockito.kotlin.mock
|
import org.mockito.kotlin.mock
|
||||||
import org.mockito.kotlin.times
|
import org.mockito.kotlin.times
|
||||||
import org.mockito.kotlin.verify
|
import org.mockito.kotlin.verify
|
||||||
|
import org.mockito.kotlin.verifyNoInteractions
|
||||||
import org.mockito.kotlin.verifyNoMoreInteractions
|
import org.mockito.kotlin.verifyNoMoreInteractions
|
||||||
import org.mockito.kotlin.verifyZeroInteractions
|
|
||||||
|
|
||||||
@Suppress("TestFunctionName")
|
@Suppress("TestFunctionName")
|
||||||
internal class SessionExpirationAdapterTest {
|
internal class SessionExpirationAdapterTest {
|
||||||
|
|
@ -24,7 +24,7 @@ internal class SessionExpirationAdapterTest {
|
||||||
@DisplayName("WHEN nothing is changed THEN delegate is not touched")
|
@DisplayName("WHEN nothing is changed THEN delegate is not touched")
|
||||||
@Test
|
@Test
|
||||||
fun verifyNoInteractionsIfNoInvocations() {
|
fun verifyNoInteractionsIfNoInvocations() {
|
||||||
verifyZeroInteractions(mockSessionExpirationListener)
|
verifyNoInteractions(mockSessionExpirationListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
@DisplayName("WHEN onSessionExpired is called THEN delegated is also called")
|
@DisplayName("WHEN onSessionExpired is called THEN delegated is also called")
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ project.ext {
|
||||||
testing_androidx_junit_version = "1.1.3"
|
testing_androidx_junit_version = "1.1.3"
|
||||||
testing_androidx_arch_core_version = "2.1.0"
|
testing_androidx_arch_core_version = "2.1.0"
|
||||||
testing_livedata_version = "1.2.0"
|
testing_livedata_version = "1.2.0"
|
||||||
testing_kotlin_mockito_version = "3.1.0"
|
testing_kotlin_mockito_version = "4.0.0"
|
||||||
testing_junit5_version = "5.7.0"
|
testing_junit5_version = "5.7.0"
|
||||||
testing_json_assert_version = "1.5.0"
|
testing_json_assert_version = "1.5.0"
|
||||||
testing_junit4_version = "4.13.2"
|
testing_junit4_version = "4.13.2"
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,8 @@ import org.mockito.kotlin.doReturn
|
||||||
import org.mockito.kotlin.mock
|
import org.mockito.kotlin.mock
|
||||||
import org.mockito.kotlin.times
|
import org.mockito.kotlin.times
|
||||||
import org.mockito.kotlin.verify
|
import org.mockito.kotlin.verify
|
||||||
|
import org.mockito.kotlin.verifyNoInteractions
|
||||||
import org.mockito.kotlin.verifyNoMoreInteractions
|
import org.mockito.kotlin.verifyNoMoreInteractions
|
||||||
import org.mockito.kotlin.verifyZeroInteractions
|
|
||||||
import org.mockito.kotlin.whenever
|
import org.mockito.kotlin.whenever
|
||||||
import retrofit2.HttpException
|
import retrofit2.HttpException
|
||||||
|
|
||||||
|
|
@ -88,7 +88,7 @@ class PlainSessionExpirationTest : KoinTest {
|
||||||
Assertions.assertEquals("login-access", contentRequestAfterRefreshed.getHeader("Authorization"))
|
Assertions.assertEquals("login-access", contentRequestAfterRefreshed.getHeader("Authorization"))
|
||||||
val expectedSavedSession = Session(accessToken = "login-access", refreshToken = "login-refresh")
|
val expectedSavedSession = Session(accessToken = "login-access", refreshToken = "login-refresh")
|
||||||
verify(mockNetworkSessionLocalStorage, times(1)).session = expectedSavedSession
|
verify(mockNetworkSessionLocalStorage, times(1)).session = expectedSavedSession
|
||||||
verifyZeroInteractions(mockNetworkSessionExpirationListener)
|
verifyNoInteractions(mockNetworkSessionExpirationListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
@DisplayName("GIVEN 401 THEN failing refresh WHEN content requested THE error is returned and callback is Called")
|
@DisplayName("GIVEN 401 THEN failing refresh WHEN content requested THE error is returned and callback is Called")
|
||||||
|
|
|
||||||
|
|
@ -27,8 +27,8 @@ import org.mockito.kotlin.doReturn
|
||||||
import org.mockito.kotlin.mock
|
import org.mockito.kotlin.mock
|
||||||
import org.mockito.kotlin.times
|
import org.mockito.kotlin.times
|
||||||
import org.mockito.kotlin.verify
|
import org.mockito.kotlin.verify
|
||||||
|
import org.mockito.kotlin.verifyNoInteractions
|
||||||
import org.mockito.kotlin.verifyNoMoreInteractions
|
import org.mockito.kotlin.verifyNoMoreInteractions
|
||||||
import org.mockito.kotlin.verifyZeroInteractions
|
|
||||||
import org.mockito.kotlin.whenever
|
import org.mockito.kotlin.whenever
|
||||||
import retrofit2.HttpException
|
import retrofit2.HttpException
|
||||||
|
|
||||||
|
|
@ -97,7 +97,7 @@ class SessionExpirationTest : KoinTest {
|
||||||
ContentData.refreshSuccessResponse.accessToken,
|
ContentData.refreshSuccessResponse.accessToken,
|
||||||
retryAfterTokenRefreshRequest.getHeader("Authorization")
|
retryAfterTokenRefreshRequest.getHeader("Authorization")
|
||||||
)
|
)
|
||||||
verifyZeroInteractions(mockNetworkSessionExpirationListener)
|
verifyNoInteractions(mockNetworkSessionExpirationListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
@DisplayName("GIVEN 401 THEN failing refresh WHEN content requested THE error is returned and callback is Called")
|
@DisplayName("GIVEN 401 THEN failing refresh WHEN content requested THE error is returned and callback is Called")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue