Issue#12 Finish ViewModel instruction set

This commit is contained in:
Gergely Hegedus 2022-01-25 20:37:35 +02:00
parent 89c741a6bb
commit d339592390
7 changed files with 472 additions and 243 deletions

View file

@ -14,7 +14,7 @@ import org.junit.jupiter.api.extension.BeforeEachCallback
import org.junit.jupiter.api.extension.ExtensionContext
/**
* Custom Junit5 Extension which replaces the [DatabaseInitialization]'s dispatcher and main dispatcher with a [TestCoroutineDispatcher]
* Custom Junit5 Extension which replaces the [DatabaseInitialization]'s dispatcher and main dispatcher with a [TestDispatcher]
*
* One can access the test dispatcher via [testDispatcher] static getter.
*/

View file

@ -44,45 +44,59 @@ internal class AuthViewModelTest {
@DisplayName("GIVEN initialized viewModel WHEN observed THEN loading false other fields are empty")
@Test
fun initialSetup() {
val usernameTestObserver = sut.username.test()
val passwordTestObserver = sut.password.test()
val loadingTestObserver = sut.loading.test()
val errorTestObserver = sut.error.test()
val navigateToHomeTestObserver = sut.navigateToHome.test()
testScheduler.advanceUntilIdle()
sut.username.test().assertNoValue()
sut.password.test().assertNoValue()
sut.loading.test().assertValue(false)
sut.error.test().assertNoValue()
sut.navigateToHome.test().assertNoValue()
usernameTestObserver.assertNoValue()
passwordTestObserver.assertNoValue()
loadingTestObserver.assertValue(false)
errorTestObserver.assertNoValue()
navigateToHomeTestObserver.assertNoValue()
}
@DisplayName("GIVEN password text WHEN onPasswordChanged is called THEN password livedata is updated")
@Test
fun whenPasswordChangedLiveDataIsUpdated() {
val usernameTestObserver = sut.username.test()
val passwordTestObserver = sut.password.test()
val loadingTestObserver = sut.loading.test()
val errorTestObserver = sut.error.test()
val navigateToHomeTestObserver = sut.navigateToHome.test()
sut.onPasswordChanged("a")
sut.onPasswordChanged("al")
testScheduler.advanceUntilIdle()
usernameTestObserver.assertNoValue()
passwordTestObserver.assertValueHistory("a", "al")
sut.username.test().assertNoValue()
sut.loading.test().assertValue(false)
sut.error.test().assertNoValue()
sut.navigateToHome.test().assertNoValue()
loadingTestObserver.assertValue(false)
errorTestObserver.assertNoValue()
navigateToHomeTestObserver.assertNoValue()
}
@DisplayName("GIVEN username text WHEN onUsernameChanged is called THEN username livedata is updated")
@Test
fun whenUsernameChangedLiveDataIsUpdated() {
val usernameTestObserver = sut.username.test()
val passwordTestObserver = sut.password.test()
val loadingTestObserver = sut.loading.test()
val errorTestObserver = sut.error.test()
val navigateToHomeTestObserver = sut.navigateToHome.test()
sut.onUsernameChanged("a")
sut.onUsernameChanged("al")
sut.onUsernameChanged("bla")
sut.onUsernameChanged("blabla")
testScheduler.advanceUntilIdle()
usernameTestObserver.assertValueHistory("a", "al")
sut.password.test().assertNoValue()
sut.loading.test().assertValue(false)
sut.error.test().assertNoValue()
sut.navigateToHome.test().assertNoValue()
usernameTestObserver.assertValueHistory("bla", "blabla")
passwordTestObserver.assertNoValue()
loadingTestObserver.assertValue(false)
errorTestObserver.assertNoValue()
navigateToHomeTestObserver.assertNoValue()
}
@DisplayName("GIVEN no password or username WHEN login is Called THEN empty credentials are used in usecase")
@ -122,6 +136,7 @@ internal class AuthViewModelTest {
}
sut.onPasswordChanged("pass")
sut.onUsernameChanged("usr")
testScheduler.advanceUntilIdle()
sut.onLogin()
testScheduler.advanceUntilIdle()
@ -134,20 +149,20 @@ internal class AuthViewModelTest {
@DisplayName("GIVEN AnswerError WHEN login called THEN error is shown")
@Test
fun loginErrorResultsInErrorState() {
fun loginUnexpectedErrorResultsInErrorState() {
runBlocking {
whenever(mockLoginUseCase.invoke(anyOrNull())).doReturn(Answer.Error(Throwable()))
}
val loadingObserver = sut.loading.test()
val errorObserver = sut.error.test()
val navigateToHomeObserver = sut.navigateToHome.test()
val loadingTestObserver = sut.loading.test()
val errorTestObserver = sut.error.test()
val navigateToHomeTestObserver = sut.navigateToHome.test()
sut.onLogin()
testScheduler.advanceUntilIdle()
loadingObserver.assertValueHistory(false, true, false)
errorObserver.assertValueHistory(Event(AuthViewModel.ErrorType.GENERAL_NETWORK_ERROR))
navigateToHomeObserver.assertNoValue()
loadingTestObserver.assertValueHistory(false, true, false)
errorTestObserver.assertValueHistory(Event(AuthViewModel.ErrorType.GENERAL_NETWORK_ERROR))
navigateToHomeTestObserver.assertNoValue()
}
@MethodSource("loginErrorStatusesArguments")
@ -159,16 +174,16 @@ internal class AuthViewModelTest {
runBlocking {
whenever(mockLoginUseCase.invoke(anyOrNull())).doReturn(Answer.Success(loginStatus))
}
val loadingObserver = sut.loading.test()
val errorObserver = sut.error.test()
val navigateToHomeObserver = sut.navigateToHome.test()
val loadingTestObserver = sut.loading.test()
val errorTestObserver = sut.error.test()
val navigateToHomeTestObserver = sut.navigateToHome.test()
sut.onLogin()
testScheduler.advanceUntilIdle()
loadingObserver.assertValueHistory(false, true, false)
errorObserver.assertValueHistory(Event(errorType))
navigateToHomeObserver.assertNoValue()
loadingTestObserver.assertValueHistory(false, true, false)
errorTestObserver.assertValueHistory(Event(errorType))
navigateToHomeTestObserver.assertNoValue()
}
@DisplayName("GIVEN answer success and login status success WHEN login called THEN navigation event is sent")
@ -177,16 +192,16 @@ internal class AuthViewModelTest {
runBlocking {
whenever(mockLoginUseCase.invoke(anyOrNull())).doReturn(Answer.Success(LoginStatus.SUCCESS))
}
val loadingObserver = sut.loading.test()
val errorObserver = sut.error.test()
val navigateToHomeObserver = sut.navigateToHome.test()
val loadingTestObserver = sut.loading.test()
val errorTestObserver = sut.error.test()
val navigateToHomeTestObserver = sut.navigateToHome.test()
sut.onLogin()
testScheduler.advanceUntilIdle()
loadingObserver.assertValueHistory(false, true, false)
errorObserver.assertNoValue()
navigateToHomeObserver.assertValueHistory(Event(Unit))
loadingTestObserver.assertValueHistory(false, true, false)
errorTestObserver.assertNoValue()
navigateToHomeTestObserver.assertValueHistory(Event(Unit))
}
companion object {

View file

@ -5,20 +5,18 @@ import org.fnives.test.showcase.core.login.LoginUseCase
import org.fnives.test.showcase.testutils.InstantExecutorExtension
import org.fnives.test.showcase.testutils.TestMainDispatcher
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Disabled
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.mockito.kotlin.mock
@Disabled("CodeKata")
@ExtendWith(InstantExecutorExtension::class, TestMainDispatcher::class)
@OptIn(ExperimentalCoroutinesApi::class)
class CodeKataAuthViewModel {
private lateinit var sut: AuthViewModel
private lateinit var mockLoginUseCase: LoginUseCase
private val testDispatcher get() = TestMainDispatcher.testDispatcher
private val testScheduler get() = TestMainDispatcher.testDispatcher.scheduler
@BeforeEach
fun setUp() {
@ -45,4 +43,29 @@ class CodeKataAuthViewModel {
@Test
fun noPasswordUsesEmptyStringInLoginUseCase() {
}
@DisplayName("WHEN login is called twice before finishing THEN use case is only called once")
@Test
fun onlyOneLoginIsSentOutWhenClickingRepeatedly() {
}
@DisplayName("GIVEN password and username WHEN login is called THEN proper credentials are used in usecase")
@Test
fun argumentsArePassedProperlyToLoginUseCase() {
}
@DisplayName("GIVEN AnswerError WHEN login called THEN error is shown")
@Test
fun loginUnexpectedErrorResultsInErrorState() {
}
@DisplayName("GIVEN answer success loginStatus INVALID_CREDENTIALS WHEN login called THEN error INVALID_CREDENTIALS is shown")
@Test
fun invalidStatusResultsInErrorState() {
}
@DisplayName("GIVEN answer success and login status success WHEN login called THEN navigation event is sent")
@Test
fun successLoginResultsInNavigation() {
}
}

View file

@ -1,11 +1,13 @@
package org.fnives.test.showcase.ui.splash
import kotlinx.coroutines.ExperimentalCoroutinesApi
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Disabled
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
@Disabled("CodeKata")
@OptIn(ExperimentalCoroutinesApi::class)
internal class CodeKataSplashViewModelTest {
@BeforeEach
@ -19,7 +21,7 @@ internal class CodeKataSplashViewModelTest {
@DisplayName("GIVEN logged in user WHEN splash started THEN after half a second navigated to home")
@Test
fun loggedInUserGoestoHome() {
fun loggedInUserGoesToHome() {
}
@DisplayName("GIVEN not logged in user WHEN splash started THEN before half a second no event is sent")