Issue#11 Adjust TestMainDispatcher extension using tests after coroutine update
This commit is contained in:
parent
3c85431d96
commit
46d9263742
5 changed files with 70 additions and 68 deletions
|
|
@ -1,7 +1,10 @@
|
||||||
package org.fnives.test.showcase.testutils
|
package org.fnives.test.showcase.testutils
|
||||||
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.test.TestCoroutineDispatcher
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.test.StandardTestDispatcher
|
||||||
|
import kotlinx.coroutines.test.TestCoroutineScheduler
|
||||||
|
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.storage.database.DatabaseInitialization
|
||||||
|
|
@ -15,12 +18,12 @@ import org.junit.jupiter.api.extension.ExtensionContext
|
||||||
*
|
*
|
||||||
* One can access the test dispatcher via [testDispatcher] static getter.
|
* One can access the test dispatcher via [testDispatcher] static getter.
|
||||||
*/
|
*/
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
class TestMainDispatcher : BeforeEachCallback, AfterEachCallback {
|
class TestMainDispatcher : BeforeEachCallback, AfterEachCallback {
|
||||||
|
|
||||||
override fun beforeEach(context: ExtensionContext?) {
|
override fun beforeEach(context: ExtensionContext?) {
|
||||||
val testDispatcher = TestCoroutineDispatcher()
|
val testDispatcher = StandardTestDispatcher(TestCoroutineScheduler())
|
||||||
privateTestDispatcher = testDispatcher
|
privateTestDispatcher = testDispatcher
|
||||||
testDispatcher.pauseDispatcher()
|
|
||||||
DatabaseInitialization.dispatcher = testDispatcher
|
DatabaseInitialization.dispatcher = testDispatcher
|
||||||
Dispatchers.setMain(testDispatcher)
|
Dispatchers.setMain(testDispatcher)
|
||||||
}
|
}
|
||||||
|
|
@ -31,8 +34,9 @@ class TestMainDispatcher : BeforeEachCallback, AfterEachCallback {
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private var privateTestDispatcher: TestCoroutineDispatcher? = null
|
private var privateTestDispatcher: TestDispatcher? = null
|
||||||
val testDispatcher: TestCoroutineDispatcher
|
val testDispatcher: TestDispatcher
|
||||||
get() = privateTestDispatcher ?: throw IllegalStateException("TestMainDispatcher is in afterEach State")
|
get() = privateTestDispatcher
|
||||||
|
?: throw IllegalStateException("TestMainDispatcher is in afterEach State")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package org.fnives.test.showcase.ui.auth
|
package org.fnives.test.showcase.ui.auth
|
||||||
|
|
||||||
import com.jraska.livedata.test
|
import com.jraska.livedata.test
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.fnives.test.showcase.core.login.LoginUseCase
|
import org.fnives.test.showcase.core.login.LoginUseCase
|
||||||
import org.fnives.test.showcase.model.auth.LoginCredentials
|
import org.fnives.test.showcase.model.auth.LoginCredentials
|
||||||
|
|
@ -27,11 +28,12 @@ import java.util.stream.Stream
|
||||||
|
|
||||||
@Suppress("TestFunctionName")
|
@Suppress("TestFunctionName")
|
||||||
@ExtendWith(InstantExecutorExtension::class, TestMainDispatcher::class)
|
@ExtendWith(InstantExecutorExtension::class, TestMainDispatcher::class)
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
internal class AuthViewModelTest {
|
internal class AuthViewModelTest {
|
||||||
|
|
||||||
private lateinit var sut: AuthViewModel
|
private lateinit var sut: AuthViewModel
|
||||||
private lateinit var mockLoginUseCase: LoginUseCase
|
private lateinit var mockLoginUseCase: LoginUseCase
|
||||||
private val testDispatcher get() = TestMainDispatcher.testDispatcher
|
private val testScheduler get() = TestMainDispatcher.testDispatcher.scheduler
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
|
|
@ -42,7 +44,7 @@ internal class AuthViewModelTest {
|
||||||
@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
|
@Test
|
||||||
fun initialSetup() {
|
fun initialSetup() {
|
||||||
testDispatcher.resumeDispatcher()
|
testScheduler.advanceUntilIdle()
|
||||||
|
|
||||||
sut.username.test().assertNoValue()
|
sut.username.test().assertNoValue()
|
||||||
sut.password.test().assertNoValue()
|
sut.password.test().assertNoValue()
|
||||||
|
|
@ -54,11 +56,11 @@ internal class AuthViewModelTest {
|
||||||
@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
|
@Test
|
||||||
fun whenPasswordChangedLiveDataIsUpdated() {
|
fun whenPasswordChangedLiveDataIsUpdated() {
|
||||||
testDispatcher.resumeDispatcher()
|
|
||||||
val passwordTestObserver = sut.password.test()
|
val passwordTestObserver = sut.password.test()
|
||||||
|
|
||||||
sut.onPasswordChanged("a")
|
sut.onPasswordChanged("a")
|
||||||
sut.onPasswordChanged("al")
|
sut.onPasswordChanged("al")
|
||||||
|
testScheduler.advanceUntilIdle()
|
||||||
|
|
||||||
passwordTestObserver.assertValueHistory("a", "al")
|
passwordTestObserver.assertValueHistory("a", "al")
|
||||||
sut.username.test().assertNoValue()
|
sut.username.test().assertNoValue()
|
||||||
|
|
@ -70,11 +72,11 @@ internal class AuthViewModelTest {
|
||||||
@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
|
@Test
|
||||||
fun whenUsernameChangedLiveDataIsUpdated() {
|
fun whenUsernameChangedLiveDataIsUpdated() {
|
||||||
testDispatcher.resumeDispatcher()
|
|
||||||
val usernameTestObserver = sut.username.test()
|
val usernameTestObserver = sut.username.test()
|
||||||
|
|
||||||
sut.onUsernameChanged("a")
|
sut.onUsernameChanged("a")
|
||||||
sut.onUsernameChanged("al")
|
sut.onUsernameChanged("al")
|
||||||
|
testScheduler.advanceUntilIdle()
|
||||||
|
|
||||||
usernameTestObserver.assertValueHistory("a", "al")
|
usernameTestObserver.assertValueHistory("a", "al")
|
||||||
sut.password.test().assertNoValue()
|
sut.password.test().assertNoValue()
|
||||||
|
|
@ -92,7 +94,7 @@ internal class AuthViewModelTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
sut.onLogin()
|
sut.onLogin()
|
||||||
testDispatcher.advanceUntilIdle()
|
testScheduler.advanceUntilIdle()
|
||||||
|
|
||||||
loadingTestObserver.assertValueHistory(false, true, false)
|
loadingTestObserver.assertValueHistory(false, true, false)
|
||||||
runBlocking { verify(mockLoginUseCase, times(1)).invoke(LoginCredentials("", "")) }
|
runBlocking { verify(mockLoginUseCase, times(1)).invoke(LoginCredentials("", "")) }
|
||||||
|
|
@ -106,7 +108,7 @@ internal class AuthViewModelTest {
|
||||||
|
|
||||||
sut.onLogin()
|
sut.onLogin()
|
||||||
sut.onLogin()
|
sut.onLogin()
|
||||||
testDispatcher.advanceUntilIdle()
|
testScheduler.advanceUntilIdle()
|
||||||
|
|
||||||
runBlocking { verify(mockLoginUseCase, times(1)).invoke(LoginCredentials("", "")) }
|
runBlocking { verify(mockLoginUseCase, times(1)).invoke(LoginCredentials("", "")) }
|
||||||
verifyNoMoreInteractions(mockLoginUseCase)
|
verifyNoMoreInteractions(mockLoginUseCase)
|
||||||
|
|
@ -122,7 +124,7 @@ internal class AuthViewModelTest {
|
||||||
sut.onUsernameChanged("usr")
|
sut.onUsernameChanged("usr")
|
||||||
|
|
||||||
sut.onLogin()
|
sut.onLogin()
|
||||||
testDispatcher.advanceUntilIdle()
|
testScheduler.advanceUntilIdle()
|
||||||
|
|
||||||
runBlocking {
|
runBlocking {
|
||||||
verify(mockLoginUseCase, times(1)).invoke(LoginCredentials("usr", "pass"))
|
verify(mockLoginUseCase, times(1)).invoke(LoginCredentials("usr", "pass"))
|
||||||
|
|
@ -141,7 +143,7 @@ internal class AuthViewModelTest {
|
||||||
val navigateToHomeObserver = sut.navigateToHome.test()
|
val navigateToHomeObserver = sut.navigateToHome.test()
|
||||||
|
|
||||||
sut.onLogin()
|
sut.onLogin()
|
||||||
testDispatcher.advanceUntilIdle()
|
testScheduler.advanceUntilIdle()
|
||||||
|
|
||||||
loadingObserver.assertValueHistory(false, true, false)
|
loadingObserver.assertValueHistory(false, true, false)
|
||||||
errorObserver.assertValueHistory(Event(AuthViewModel.ErrorType.GENERAL_NETWORK_ERROR))
|
errorObserver.assertValueHistory(Event(AuthViewModel.ErrorType.GENERAL_NETWORK_ERROR))
|
||||||
|
|
@ -162,7 +164,7 @@ internal class AuthViewModelTest {
|
||||||
val navigateToHomeObserver = sut.navigateToHome.test()
|
val navigateToHomeObserver = sut.navigateToHome.test()
|
||||||
|
|
||||||
sut.onLogin()
|
sut.onLogin()
|
||||||
testDispatcher.advanceUntilIdle()
|
testScheduler.advanceUntilIdle()
|
||||||
|
|
||||||
loadingObserver.assertValueHistory(false, true, false)
|
loadingObserver.assertValueHistory(false, true, false)
|
||||||
errorObserver.assertValueHistory(Event(errorType))
|
errorObserver.assertValueHistory(Event(errorType))
|
||||||
|
|
@ -180,7 +182,7 @@ internal class AuthViewModelTest {
|
||||||
val navigateToHomeObserver = sut.navigateToHome.test()
|
val navigateToHomeObserver = sut.navigateToHome.test()
|
||||||
|
|
||||||
sut.onLogin()
|
sut.onLogin()
|
||||||
testDispatcher.advanceUntilIdle()
|
testScheduler.advanceUntilIdle()
|
||||||
|
|
||||||
loadingObserver.assertValueHistory(false, true, false)
|
loadingObserver.assertValueHistory(false, true, false)
|
||||||
errorObserver.assertNoValue()
|
errorObserver.assertNoValue()
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package org.fnives.test.showcase.ui.home
|
package org.fnives.test.showcase.ui.home
|
||||||
|
|
||||||
import com.jraska.livedata.test
|
import com.jraska.livedata.test
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.flow.flowOf
|
import kotlinx.coroutines.flow.flowOf
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.fnives.test.showcase.core.content.AddContentToFavouriteUseCase
|
import org.fnives.test.showcase.core.content.AddContentToFavouriteUseCase
|
||||||
|
|
@ -29,6 +30,7 @@ import org.mockito.kotlin.whenever
|
||||||
|
|
||||||
@Suppress("TestFunctionName")
|
@Suppress("TestFunctionName")
|
||||||
@ExtendWith(InstantExecutorExtension::class, TestMainDispatcher::class)
|
@ExtendWith(InstantExecutorExtension::class, TestMainDispatcher::class)
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
internal class MainViewModelTest {
|
internal class MainViewModelTest {
|
||||||
|
|
||||||
private lateinit var sut: MainViewModel
|
private lateinit var sut: MainViewModel
|
||||||
|
|
@ -37,7 +39,7 @@ internal class MainViewModelTest {
|
||||||
private lateinit var mockFetchContentUseCase: FetchContentUseCase
|
private lateinit var mockFetchContentUseCase: FetchContentUseCase
|
||||||
private lateinit var mockAddContentToFavouriteUseCase: AddContentToFavouriteUseCase
|
private lateinit var mockAddContentToFavouriteUseCase: AddContentToFavouriteUseCase
|
||||||
private lateinit var mockRemoveContentFromFavouritesUseCase: RemoveContentFromFavouritesUseCase
|
private lateinit var mockRemoveContentFromFavouritesUseCase: RemoveContentFromFavouritesUseCase
|
||||||
private val testDispatcher get() = TestMainDispatcher.testDispatcher
|
private val testScheduler get() = TestMainDispatcher.testDispatcher.scheduler
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
|
|
@ -46,7 +48,6 @@ internal class MainViewModelTest {
|
||||||
mockFetchContentUseCase = mock()
|
mockFetchContentUseCase = mock()
|
||||||
mockAddContentToFavouriteUseCase = mock()
|
mockAddContentToFavouriteUseCase = mock()
|
||||||
mockRemoveContentFromFavouritesUseCase = mock()
|
mockRemoveContentFromFavouritesUseCase = mock()
|
||||||
testDispatcher.pauseDispatcher()
|
|
||||||
sut = MainViewModel(
|
sut = MainViewModel(
|
||||||
getAllContentUseCase = mockGetAllContentUseCase,
|
getAllContentUseCase = mockGetAllContentUseCase,
|
||||||
logoutUseCase = mockLogoutUseCase,
|
logoutUseCase = mockLogoutUseCase,
|
||||||
|
|
@ -69,13 +70,16 @@ internal class MainViewModelTest {
|
||||||
@Test
|
@Test
|
||||||
fun loadingDataShowsInLoadingUIState() {
|
fun loadingDataShowsInLoadingUIState() {
|
||||||
whenever(mockGetAllContentUseCase.get()).doReturn(flowOf(Resource.Loading()))
|
whenever(mockGetAllContentUseCase.get()).doReturn(flowOf(Resource.Loading()))
|
||||||
testDispatcher.resumeDispatcher()
|
val errorMessageTestObserver = sut.errorMessage.test()
|
||||||
testDispatcher.advanceUntilIdle()
|
val contentTestObserver = sut.content.test()
|
||||||
|
val loadingTestObserver = sut.loading.test()
|
||||||
|
val navigateToAuthTestObserver = sut.navigateToAuth.test()
|
||||||
|
testScheduler.advanceUntilIdle()
|
||||||
|
|
||||||
sut.errorMessage.test().assertValue(false)
|
errorMessageTestObserver.assertValue(false)
|
||||||
sut.content.test().assertNoValue()
|
contentTestObserver.assertNoValue()
|
||||||
sut.loading.test().assertValue(true)
|
loadingTestObserver.assertValue(true)
|
||||||
sut.navigateToAuth.test().assertNoValue()
|
navigateToAuthTestObserver.assertNoValue()
|
||||||
}
|
}
|
||||||
|
|
||||||
@DisplayName("GIVEN loading then data WHEN observing content THEN proper states are shown")
|
@DisplayName("GIVEN loading then data WHEN observing content THEN proper states are shown")
|
||||||
|
|
@ -85,13 +89,13 @@ internal class MainViewModelTest {
|
||||||
val errorMessageTestObserver = sut.errorMessage.test()
|
val errorMessageTestObserver = sut.errorMessage.test()
|
||||||
val contentTestObserver = sut.content.test()
|
val contentTestObserver = sut.content.test()
|
||||||
val loadingTestObserver = sut.loading.test()
|
val loadingTestObserver = sut.loading.test()
|
||||||
testDispatcher.resumeDispatcher()
|
val navigateToAuthTestObserver = sut.navigateToAuth.test()
|
||||||
testDispatcher.advanceUntilIdle()
|
testScheduler.advanceUntilIdle()
|
||||||
|
|
||||||
errorMessageTestObserver.assertValueHistory(false)
|
errorMessageTestObserver.assertValueHistory(false)
|
||||||
contentTestObserver.assertValueHistory(listOf())
|
contentTestObserver.assertValueHistory(listOf())
|
||||||
loadingTestObserver.assertValueHistory(true, false)
|
loadingTestObserver.assertValueHistory(true, false)
|
||||||
sut.navigateToAuth.test().assertNoValue()
|
navigateToAuthTestObserver.assertNoValue()
|
||||||
}
|
}
|
||||||
|
|
||||||
@DisplayName("GIVEN loading then error WHEN observing content THEN proper states are shown")
|
@DisplayName("GIVEN loading then error WHEN observing content THEN proper states are shown")
|
||||||
|
|
@ -101,13 +105,13 @@ internal class MainViewModelTest {
|
||||||
val errorMessageTestObserver = sut.errorMessage.test()
|
val errorMessageTestObserver = sut.errorMessage.test()
|
||||||
val contentTestObserver = sut.content.test()
|
val contentTestObserver = sut.content.test()
|
||||||
val loadingTestObserver = sut.loading.test()
|
val loadingTestObserver = sut.loading.test()
|
||||||
testDispatcher.resumeDispatcher()
|
val navigateToAuthTestObserver = sut.navigateToAuth.test()
|
||||||
testDispatcher.advanceUntilIdle()
|
testScheduler.advanceUntilIdle()
|
||||||
|
|
||||||
errorMessageTestObserver.assertValueHistory(false, true)
|
errorMessageTestObserver.assertValueHistory(false, true)
|
||||||
contentTestObserver.assertValueHistory(emptyList())
|
contentTestObserver.assertValueHistory(emptyList())
|
||||||
loadingTestObserver.assertValueHistory(true, false)
|
loadingTestObserver.assertValueHistory(true, false)
|
||||||
sut.navigateToAuth.test().assertNoValue()
|
navigateToAuthTestObserver.assertNoValue()
|
||||||
}
|
}
|
||||||
|
|
||||||
@DisplayName("GIVEN loading then error then loading then data WHEN observing content THEN proper states are shown")
|
@DisplayName("GIVEN loading then error then loading then data WHEN observing content THEN proper states are shown")
|
||||||
|
|
@ -127,13 +131,13 @@ internal class MainViewModelTest {
|
||||||
val errorMessageTestObserver = sut.errorMessage.test()
|
val errorMessageTestObserver = sut.errorMessage.test()
|
||||||
val contentTestObserver = sut.content.test()
|
val contentTestObserver = sut.content.test()
|
||||||
val loadingTestObserver = sut.loading.test()
|
val loadingTestObserver = sut.loading.test()
|
||||||
testDispatcher.resumeDispatcher()
|
val navigateToAuthTestObserver = sut.navigateToAuth.test()
|
||||||
testDispatcher.advanceUntilIdle()
|
testScheduler.advanceUntilIdle()
|
||||||
|
|
||||||
errorMessageTestObserver.assertValueHistory(false, true, false)
|
errorMessageTestObserver.assertValueHistory(false, true, false)
|
||||||
contentTestObserver.assertValueHistory(emptyList(), content)
|
contentTestObserver.assertValueHistory(emptyList(), content)
|
||||||
loadingTestObserver.assertValueHistory(true, false, true, false)
|
loadingTestObserver.assertValueHistory(true, false, true, false)
|
||||||
sut.navigateToAuth.test().assertNoValue()
|
navigateToAuthTestObserver.assertNoValue()
|
||||||
}
|
}
|
||||||
|
|
||||||
@DisplayName("GIVEN loading viewModel WHEN refreshing THEN usecase is not called")
|
@DisplayName("GIVEN loading viewModel WHEN refreshing THEN usecase is not called")
|
||||||
|
|
@ -141,11 +145,10 @@ internal class MainViewModelTest {
|
||||||
fun fetchIsIgnoredIfViewModelIsStillLoading() {
|
fun fetchIsIgnoredIfViewModelIsStillLoading() {
|
||||||
whenever(mockGetAllContentUseCase.get()).doReturn(flowOf(Resource.Loading()))
|
whenever(mockGetAllContentUseCase.get()).doReturn(flowOf(Resource.Loading()))
|
||||||
sut.content.test()
|
sut.content.test()
|
||||||
testDispatcher.resumeDispatcher()
|
testScheduler.advanceUntilIdle()
|
||||||
testDispatcher.advanceUntilIdle()
|
|
||||||
|
|
||||||
sut.onRefresh()
|
sut.onRefresh()
|
||||||
testDispatcher.advanceUntilIdle()
|
testScheduler.advanceUntilIdle()
|
||||||
|
|
||||||
verifyZeroInteractions(mockFetchContentUseCase)
|
verifyZeroInteractions(mockFetchContentUseCase)
|
||||||
}
|
}
|
||||||
|
|
@ -155,11 +158,10 @@ internal class MainViewModelTest {
|
||||||
fun fetchIsCalledIfViewModelIsLoaded() {
|
fun fetchIsCalledIfViewModelIsLoaded() {
|
||||||
whenever(mockGetAllContentUseCase.get()).doReturn(flowOf())
|
whenever(mockGetAllContentUseCase.get()).doReturn(flowOf())
|
||||||
sut.content.test()
|
sut.content.test()
|
||||||
testDispatcher.resumeDispatcher()
|
testScheduler.advanceUntilIdle()
|
||||||
testDispatcher.advanceUntilIdle()
|
|
||||||
|
|
||||||
sut.onRefresh()
|
sut.onRefresh()
|
||||||
testDispatcher.advanceUntilIdle()
|
testScheduler.advanceUntilIdle()
|
||||||
|
|
||||||
verify(mockFetchContentUseCase, times(1)).invoke()
|
verify(mockFetchContentUseCase, times(1)).invoke()
|
||||||
verifyNoMoreInteractions(mockFetchContentUseCase)
|
verifyNoMoreInteractions(mockFetchContentUseCase)
|
||||||
|
|
@ -170,11 +172,10 @@ internal class MainViewModelTest {
|
||||||
fun loadingViewModelStillCalsLogout() {
|
fun loadingViewModelStillCalsLogout() {
|
||||||
whenever(mockGetAllContentUseCase.get()).doReturn(flowOf(Resource.Loading()))
|
whenever(mockGetAllContentUseCase.get()).doReturn(flowOf(Resource.Loading()))
|
||||||
sut.content.test()
|
sut.content.test()
|
||||||
testDispatcher.resumeDispatcher()
|
testScheduler.advanceUntilIdle()
|
||||||
testDispatcher.advanceUntilIdle()
|
|
||||||
|
|
||||||
sut.onLogout()
|
sut.onLogout()
|
||||||
testDispatcher.advanceUntilIdle()
|
testScheduler.advanceUntilIdle()
|
||||||
|
|
||||||
runBlocking { verify(mockLogoutUseCase, times(1)).invoke() }
|
runBlocking { verify(mockLogoutUseCase, times(1)).invoke() }
|
||||||
verifyNoMoreInteractions(mockLogoutUseCase)
|
verifyNoMoreInteractions(mockLogoutUseCase)
|
||||||
|
|
@ -185,11 +186,10 @@ internal class MainViewModelTest {
|
||||||
fun nonLoadingViewModelStillCalsLogout() {
|
fun nonLoadingViewModelStillCalsLogout() {
|
||||||
whenever(mockGetAllContentUseCase.get()).doReturn(flowOf())
|
whenever(mockGetAllContentUseCase.get()).doReturn(flowOf())
|
||||||
sut.content.test()
|
sut.content.test()
|
||||||
testDispatcher.resumeDispatcher()
|
testScheduler.advanceUntilIdle()
|
||||||
testDispatcher.advanceUntilIdle()
|
|
||||||
|
|
||||||
sut.onLogout()
|
sut.onLogout()
|
||||||
testDispatcher.advanceUntilIdle()
|
testScheduler.advanceUntilIdle()
|
||||||
|
|
||||||
runBlocking { verify(mockLogoutUseCase, times(1)).invoke() }
|
runBlocking { verify(mockLogoutUseCase, times(1)).invoke() }
|
||||||
verifyNoMoreInteractions(mockLogoutUseCase)
|
verifyNoMoreInteractions(mockLogoutUseCase)
|
||||||
|
|
@ -204,11 +204,10 @@ internal class MainViewModelTest {
|
||||||
)
|
)
|
||||||
whenever(mockGetAllContentUseCase.get()).doReturn(flowOf(Resource.Success(contents)))
|
whenever(mockGetAllContentUseCase.get()).doReturn(flowOf(Resource.Success(contents)))
|
||||||
sut.content.test()
|
sut.content.test()
|
||||||
testDispatcher.resumeDispatcher()
|
testScheduler.advanceUntilIdle()
|
||||||
testDispatcher.advanceUntilIdle()
|
|
||||||
|
|
||||||
sut.onFavouriteToggleClicked(ContentId("c"))
|
sut.onFavouriteToggleClicked(ContentId("c"))
|
||||||
testDispatcher.advanceUntilIdle()
|
testScheduler.advanceUntilIdle()
|
||||||
|
|
||||||
verifyZeroInteractions(mockRemoveContentFromFavouritesUseCase)
|
verifyZeroInteractions(mockRemoveContentFromFavouritesUseCase)
|
||||||
verifyZeroInteractions(mockAddContentToFavouriteUseCase)
|
verifyZeroInteractions(mockAddContentToFavouriteUseCase)
|
||||||
|
|
@ -223,11 +222,10 @@ internal class MainViewModelTest {
|
||||||
)
|
)
|
||||||
whenever(mockGetAllContentUseCase.get()).doReturn(flowOf(Resource.Success(contents)))
|
whenever(mockGetAllContentUseCase.get()).doReturn(flowOf(Resource.Success(contents)))
|
||||||
sut.content.test()
|
sut.content.test()
|
||||||
testDispatcher.resumeDispatcher()
|
testScheduler.advanceUntilIdle()
|
||||||
testDispatcher.advanceUntilIdle()
|
|
||||||
|
|
||||||
sut.onFavouriteToggleClicked(ContentId("b"))
|
sut.onFavouriteToggleClicked(ContentId("b"))
|
||||||
testDispatcher.advanceUntilIdle()
|
testScheduler.advanceUntilIdle()
|
||||||
|
|
||||||
runBlocking { verify(mockRemoveContentFromFavouritesUseCase, times(1)).invoke(ContentId("b")) }
|
runBlocking { verify(mockRemoveContentFromFavouritesUseCase, times(1)).invoke(ContentId("b")) }
|
||||||
verifyNoMoreInteractions(mockRemoveContentFromFavouritesUseCase)
|
verifyNoMoreInteractions(mockRemoveContentFromFavouritesUseCase)
|
||||||
|
|
@ -243,11 +241,10 @@ internal class MainViewModelTest {
|
||||||
)
|
)
|
||||||
whenever(mockGetAllContentUseCase.get()).doReturn(flowOf(Resource.Success(contents)))
|
whenever(mockGetAllContentUseCase.get()).doReturn(flowOf(Resource.Success(contents)))
|
||||||
sut.content.test()
|
sut.content.test()
|
||||||
testDispatcher.resumeDispatcher()
|
testScheduler.advanceUntilIdle()
|
||||||
testDispatcher.advanceUntilIdle()
|
|
||||||
|
|
||||||
sut.onFavouriteToggleClicked(ContentId("a"))
|
sut.onFavouriteToggleClicked(ContentId("a"))
|
||||||
testDispatcher.advanceUntilIdle()
|
testScheduler.advanceUntilIdle()
|
||||||
|
|
||||||
verifyZeroInteractions(mockRemoveContentFromFavouritesUseCase)
|
verifyZeroInteractions(mockRemoveContentFromFavouritesUseCase)
|
||||||
runBlocking { verify(mockAddContentToFavouriteUseCase, times(1)).invoke(ContentId("a")) }
|
runBlocking { verify(mockAddContentToFavouriteUseCase, times(1)).invoke(ContentId("a")) }
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package org.fnives.test.showcase.ui.splash
|
package org.fnives.test.showcase.ui.splash
|
||||||
|
|
||||||
import com.jraska.livedata.test
|
import com.jraska.livedata.test
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import org.fnives.test.showcase.core.login.IsUserLoggedInUseCase
|
import org.fnives.test.showcase.core.login.IsUserLoggedInUseCase
|
||||||
import org.fnives.test.showcase.testutils.InstantExecutorExtension
|
import org.fnives.test.showcase.testutils.InstantExecutorExtension
|
||||||
import org.fnives.test.showcase.testutils.TestMainDispatcher
|
import org.fnives.test.showcase.testutils.TestMainDispatcher
|
||||||
|
|
@ -14,11 +15,12 @@ import org.mockito.kotlin.mock
|
||||||
import org.mockito.kotlin.whenever
|
import org.mockito.kotlin.whenever
|
||||||
|
|
||||||
@ExtendWith(InstantExecutorExtension::class, TestMainDispatcher::class)
|
@ExtendWith(InstantExecutorExtension::class, TestMainDispatcher::class)
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
internal class SplashViewModelTest {
|
internal class SplashViewModelTest {
|
||||||
|
|
||||||
private lateinit var mockIsUserLoggedInUseCase: IsUserLoggedInUseCase
|
private lateinit var mockIsUserLoggedInUseCase: IsUserLoggedInUseCase
|
||||||
private lateinit var sut: SplashViewModel
|
private lateinit var sut: SplashViewModel
|
||||||
private val testCoroutineDispatcher get() = TestMainDispatcher.testDispatcher
|
private val testScheduler get() = TestMainDispatcher.testDispatcher.scheduler
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
|
|
@ -30,29 +32,32 @@ internal class SplashViewModelTest {
|
||||||
@Test
|
@Test
|
||||||
fun loggedOutUserGoesToAuthentication() {
|
fun loggedOutUserGoesToAuthentication() {
|
||||||
whenever(mockIsUserLoggedInUseCase.invoke()).doReturn(false)
|
whenever(mockIsUserLoggedInUseCase.invoke()).doReturn(false)
|
||||||
|
val navigateToTestObserver = sut.navigateTo.test()
|
||||||
|
|
||||||
testCoroutineDispatcher.advanceTimeBy(500)
|
testScheduler.advanceTimeBy(501)
|
||||||
|
|
||||||
sut.navigateTo.test().assertValue(Event(SplashViewModel.NavigateTo.AUTHENTICATION))
|
navigateToTestObserver.assertValueHistory(Event(SplashViewModel.NavigateTo.AUTHENTICATION))
|
||||||
}
|
}
|
||||||
|
|
||||||
@DisplayName("GIVEN logged in user WHEN splash started THEN after half a second navigated to home")
|
@DisplayName("GIVEN logged in user WHEN splash started THEN after half a second navigated to home")
|
||||||
@Test
|
@Test
|
||||||
fun loggedInUserGoestoHome() {
|
fun loggedInUserGoesToHome() {
|
||||||
whenever(mockIsUserLoggedInUseCase.invoke()).doReturn(true)
|
whenever(mockIsUserLoggedInUseCase.invoke()).doReturn(true)
|
||||||
|
val navigateToTestObserver = sut.navigateTo.test()
|
||||||
|
|
||||||
testCoroutineDispatcher.advanceTimeBy(500)
|
testScheduler.advanceTimeBy(501)
|
||||||
|
|
||||||
sut.navigateTo.test().assertValue(Event(SplashViewModel.NavigateTo.HOME))
|
navigateToTestObserver.assertValueHistory(Event(SplashViewModel.NavigateTo.HOME))
|
||||||
}
|
}
|
||||||
|
|
||||||
@DisplayName("GIVEN not logged in user WHEN splash started THEN before half a second no event is sent")
|
@DisplayName("GIVEN not logged in user WHEN splash started THEN before half a second no event is sent")
|
||||||
@Test
|
@Test
|
||||||
fun withoutEnoughTimeNoNavigationHappens() {
|
fun withoutEnoughTimeNoNavigationHappens() {
|
||||||
whenever(mockIsUserLoggedInUseCase.invoke()).doReturn(false)
|
whenever(mockIsUserLoggedInUseCase.invoke()).doReturn(false)
|
||||||
|
val navigateToTestObserver = sut.navigateTo.test()
|
||||||
|
|
||||||
testCoroutineDispatcher.advanceTimeBy(100)
|
testScheduler.advanceTimeBy(500)
|
||||||
|
|
||||||
sut.navigateTo.test().assertNoValue()
|
navigateToTestObserver.assertNoValue()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ import org.fnives.test.showcase.ui.auth.AuthViewModel
|
||||||
import org.fnives.test.showcase.ui.home.MainViewModel
|
import org.fnives.test.showcase.ui.home.MainViewModel
|
||||||
import org.fnives.test.showcase.ui.splash.SplashViewModel
|
import org.fnives.test.showcase.ui.splash.SplashViewModel
|
||||||
import org.junit.jupiter.api.AfterEach
|
import org.junit.jupiter.api.AfterEach
|
||||||
import org.junit.jupiter.api.BeforeEach
|
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import org.junit.jupiter.api.extension.ExtendWith
|
import org.junit.jupiter.api.extension.ExtendWith
|
||||||
import org.koin.android.ext.koin.androidContext
|
import org.koin.android.ext.koin.androidContext
|
||||||
|
|
@ -28,11 +27,6 @@ class DITest : KoinTest {
|
||||||
private val mainViewModel by inject<MainViewModel>()
|
private val mainViewModel by inject<MainViewModel>()
|
||||||
private val splashViewModel by inject<SplashViewModel>()
|
private val splashViewModel by inject<SplashViewModel>()
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
fun setUp() {
|
|
||||||
TestMainDispatcher.testDispatcher.pauseDispatcher()
|
|
||||||
}
|
|
||||||
|
|
||||||
@AfterEach
|
@AfterEach
|
||||||
fun tearDown() {
|
fun tearDown() {
|
||||||
stopKoin()
|
stopKoin()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue