issue#6 Add DisplayName annotation to ViewModel tests in app module

This commit is contained in:
Gergely Hegedus 2022-01-04 14:34:46 +02:00
parent e7f840a1b9
commit ab3e6a64f0
17 changed files with 92 additions and 53 deletions

View file

@ -159,4 +159,6 @@ dependencies {
androidTestImplementation "com.google.dagger:hilt-android-testing:$hilt_version" androidTestImplementation "com.google.dagger:hilt-android-testing:$hilt_version"
kaptAndroidTest "com.google.dagger:hilt-compiler:$hilt_version" kaptAndroidTest "com.google.dagger:hilt-compiler:$hilt_version"
androidTestImplementation project(":network") // hilt needs it androidTestImplementation project(":network") // hilt needs it
implementation "io.reactivex.rxjava3:rxjava:3.1.2"
} }

View file

@ -3,6 +3,7 @@ package org.fnives.test.showcase.ui.home
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.distinctUntilChanged
import androidx.lifecycle.liveData import androidx.lifecycle.liveData
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
@ -52,7 +53,7 @@ class MainViewModel @Inject constructor(
} }
val content: LiveData<List<FavouriteContent>> = _content val content: LiveData<List<FavouriteContent>> = _content
private val _errorMessage = MutableLiveData<Boolean>(false) private val _errorMessage = MutableLiveData<Boolean>(false)
val errorMessage: LiveData<Boolean> = _errorMessage val errorMessage: LiveData<Boolean> = _errorMessage.distinctUntilChanged()
private val _navigateToAuth = MutableLiveData<Event<Unit>>() private val _navigateToAuth = MutableLiveData<Event<Unit>>()
val navigateToAuth: LiveData<Event<Unit>> = _navigateToAuth val navigateToAuth: LiveData<Event<Unit>> = _navigateToAuth

View file

@ -6,6 +6,14 @@ 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
/**
* Junit5 Version of InstantTaskExecutorRule from Junit4
*
* reference: https://developer.android.com/reference/androidx/arch/core/executor/testing/InstantTaskExecutorRule
*
* A JUnit5 Extensions that swaps the background executor used by the Architecture Components with a different one which executes each task synchronously.
* You can use this extension for your host side tests that use Architecture Components.
*/
class InstantExecutorExtension : BeforeEachCallback, AfterEachCallback { class InstantExecutorExtension : BeforeEachCallback, AfterEachCallback {
override fun beforeEach(context: ExtensionContext?) { override fun beforeEach(context: ExtensionContext?) {

View file

@ -5,10 +5,16 @@ import kotlinx.coroutines.test.TestCoroutineDispatcher
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.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 [TestCoroutineDispatcher]
*
* One can access the test dispatcher via [testDispatcher] static getter.
*/
class TestMainDispatcher : BeforeEachCallback, AfterEachCallback { class TestMainDispatcher : BeforeEachCallback, AfterEachCallback {
override fun beforeEach(context: ExtensionContext?) { override fun beforeEach(context: ExtensionContext?) {

View file

@ -39,7 +39,7 @@ internal class AuthViewModelTest {
sut = AuthViewModel(mockLoginUseCase) sut = AuthViewModel(mockLoginUseCase)
} }
@DisplayName("GIVEN_initialized_viewModel_WHEN_observed_THEN_loading_false_other_fields_are_empty") @DisplayName("GIVEN initialized viewModel WHEN observed THEN loading false other fields are empty")
@Test @Test
fun initialSetup() { fun initialSetup() {
testDispatcher.resumeDispatcher() testDispatcher.resumeDispatcher()
@ -51,7 +51,7 @@ internal class AuthViewModelTest {
sut.navigateToHome.test().assertNoValue() sut.navigateToHome.test().assertNoValue()
} }
@DisplayName("GIVEN_password_text_WHEN_onPasswordChanged_is_called_THEN_password_livedata_is_updated") @DisplayName("GIVEN password text WHEN onPasswordChanged is called THEN password livedata is updated")
@Test @Test
fun whenPasswordChangedLiveDataIsUpdated() { fun whenPasswordChangedLiveDataIsUpdated() {
testDispatcher.resumeDispatcher() testDispatcher.resumeDispatcher()
@ -67,7 +67,7 @@ internal class AuthViewModelTest {
sut.navigateToHome.test().assertNoValue() sut.navigateToHome.test().assertNoValue()
} }
@DisplayName("GIVEN_username_text_WHEN_onUsernameChanged_is_called_THEN_username_livedata_is_updated") @DisplayName("GIVEN username text WHEN onUsernameChanged is called THEN username livedata is updated")
@Test @Test
fun whenUsernameChangedLiveDataIsUpdated() { fun whenUsernameChangedLiveDataIsUpdated() {
testDispatcher.resumeDispatcher() testDispatcher.resumeDispatcher()
@ -83,7 +83,7 @@ internal class AuthViewModelTest {
sut.navigateToHome.test().assertNoValue() sut.navigateToHome.test().assertNoValue()
} }
@DisplayName("GIVEN_no_password_or_username_WHEN_login_is_Called_THEN_empty_credentials_are_used_in_usecase") @DisplayName("GIVEN no password or username WHEN login is Called THEN empty credentials are used in usecase")
@Test @Test
fun noPasswordUsesEmptyStringInLoginUseCase() { fun noPasswordUsesEmptyStringInLoginUseCase() {
val loadingTestObserver = sut.loading.test() val loadingTestObserver = sut.loading.test()
@ -99,8 +99,9 @@ internal class AuthViewModelTest {
verifyNoMoreInteractions(mockLoginUseCase) verifyNoMoreInteractions(mockLoginUseCase)
} }
@DisplayName("WHEN login is called twice before finishing THEN use case is only called once")
@Test @Test
fun WHEN_login_is_Called_twice_THEN_use_case_is_only_called_once() { fun onlyOneLoginIsSentOutWhenClickingRepeatedly() {
runBlocking { whenever(mockLoginUseCase.invoke(anyOrNull())).doReturn(Answer.Error(Throwable())) } runBlocking { whenever(mockLoginUseCase.invoke(anyOrNull())).doReturn(Answer.Error(Throwable())) }
sut.onLogin() sut.onLogin()
@ -111,8 +112,9 @@ internal class AuthViewModelTest {
verifyNoMoreInteractions(mockLoginUseCase) verifyNoMoreInteractions(mockLoginUseCase)
} }
@DisplayName("GIVEN password and username WHEN login is called THEN proper credentials are used in usecase")
@Test @Test
fun GIVEN_password_and_username_WHEN_login_is_Called_THEN_not_empty_credentials_are_used_in_usecase() { fun argumentsArePassedProperlyToLoginUseCase() {
runBlocking { runBlocking {
whenever(mockLoginUseCase.invoke(anyOrNull())).doReturn(Answer.Error(Throwable())) whenever(mockLoginUseCase.invoke(anyOrNull())).doReturn(Answer.Error(Throwable()))
} }
@ -128,8 +130,9 @@ internal class AuthViewModelTest {
verifyNoMoreInteractions(mockLoginUseCase) verifyNoMoreInteractions(mockLoginUseCase)
} }
@DisplayName("GIVEN AnswerError WHEN login called THEN error is shown")
@Test @Test
fun GIVEN_answer_error_WHEN_login_called_THEN_error_is_shown() { fun loginErrorResultsInErrorState() {
runBlocking { runBlocking {
whenever(mockLoginUseCase.invoke(anyOrNull())).doReturn(Answer.Error(Throwable())) whenever(mockLoginUseCase.invoke(anyOrNull())).doReturn(Answer.Error(Throwable()))
} }
@ -146,8 +149,8 @@ internal class AuthViewModelTest {
} }
@MethodSource("loginErrorStatusesArguments") @MethodSource("loginErrorStatusesArguments")
@ParameterizedTest(name = "GIVEN_answer_success_loginStatus_{0}_WHEN_login_called_THEN_error_{1}_is_shown") @ParameterizedTest(name = "GIVEN answer success loginStatus {0} WHEN login called THEN error {1} is shown")
fun GIVEN_answer_success_invalid_loginStatus_WHEN_login_called_THEN_error_is_shown( fun invalidStatusResultsInErrorState(
loginStatus: LoginStatus, loginStatus: LoginStatus,
errorType: AuthViewModel.ErrorType errorType: AuthViewModel.ErrorType
) { ) {
@ -166,8 +169,9 @@ internal class AuthViewModelTest {
navigateToHomeObserver.assertNoValue() navigateToHomeObserver.assertNoValue()
} }
@DisplayName("GIVEN answer success and login status success WHEN login called THEN navigation event is sent")
@Test @Test
fun GIVEN_answer_success_login_status_success_WHEN_login_called_THEN_navigation_event_is_sent() { fun successLoginResultsInNavigation() {
runBlocking { runBlocking {
whenever(mockLoginUseCase.invoke(anyOrNull())).doReturn(Answer.Success(LoginStatus.SUCCESS)) whenever(mockLoginUseCase.invoke(anyOrNull())).doReturn(Answer.Success(LoginStatus.SUCCESS))
} }

View file

@ -24,22 +24,22 @@ class CodeKataAuthViewModel {
sut = AuthViewModel(mockLoginUseCase) sut = AuthViewModel(mockLoginUseCase)
} }
@DisplayName("GIVEN_initialized_viewModel_WHEN_observed_THEN_loading_false_other_fields_are_empty") @DisplayName("GIVEN initialized viewModel WHEN observed THEN loading false other fields are empty")
@Test @Test
fun initialSetup() { fun initialSetup() {
} }
@DisplayName("GIVEN_password_text_WHEN_onPasswordChanged_is_called_THEN_password_livedata_is_updated") @DisplayName("GIVEN password text WHEN onPasswordChanged is called THEN password livedata is updated")
@Test @Test
fun whenPasswordChangedLiveDataIsUpdated() { fun whenPasswordChangedLiveDataIsUpdated() {
} }
@DisplayName("GIVEN_username_text_WHEN_onUsernameChanged_is_called_THEN_username_livedata_is_updated") @DisplayName("GIVEN username text WHEN onUsernameChanged is called THEN username livedata is updated")
@Test @Test
fun whenUsernameChangedLiveDataIsUpdated() { fun whenUsernameChangedLiveDataIsUpdated() {
} }
@DisplayName("GIVEN_no_password_or_username_WHEN_login_is_Called_THEN_empty_credentials_are_used_in_usecase") @DisplayName("GIVEN no password or username WHEN login is Called THEN empty credentials are used in usecase")
@Test @Test
fun noPasswordUsesEmptyStringInLoginUseCase() { fun noPasswordUsesEmptyStringInLoginUseCase() {
} }

View file

@ -16,6 +16,7 @@ import org.fnives.test.showcase.model.shared.Resource
import org.fnives.test.showcase.testutils.InstantExecutorExtension import org.fnives.test.showcase.testutils.InstantExecutorExtension
import org.fnives.test.showcase.testutils.TestMainDispatcher import org.fnives.test.showcase.testutils.TestMainDispatcher
import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.DisplayName
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.mockito.kotlin.doReturn import org.mockito.kotlin.doReturn
@ -55,16 +56,18 @@ internal class MainViewModelTest {
) )
} }
@DisplayName("WHEN initialization THEN error false other states empty")
@Test @Test
fun WHEN_initialization_THEN_error_false_other_states_empty() { fun initialStateIsCorrect() {
sut.errorMessage.test().assertValue(false) sut.errorMessage.test().assertValue(false)
sut.content.test().assertNoValue() sut.content.test().assertNoValue()
sut.loading.test().assertNoValue() sut.loading.test().assertNoValue()
sut.navigateToAuth.test().assertNoValue() sut.navigateToAuth.test().assertNoValue()
} }
@DisplayName("GIVEN initialized viewModel WHEN loading is returned THEN loading is shown")
@Test @Test
fun GIVEN_initialized_viewModel_WHEN_loading_is_returned_THEN_loading_is_shown() { fun loadingDataShowsInLoadingUIState() {
whenever(mockGetAllContentUseCase.get()).doReturn(flowOf(Resource.Loading())) whenever(mockGetAllContentUseCase.get()).doReturn(flowOf(Resource.Loading()))
testDispatcher.resumeDispatcher() testDispatcher.resumeDispatcher()
testDispatcher.advanceUntilIdle() testDispatcher.advanceUntilIdle()
@ -75,8 +78,9 @@ internal class MainViewModelTest {
sut.navigateToAuth.test().assertNoValue() sut.navigateToAuth.test().assertNoValue()
} }
@DisplayName("GIVEN loading then data WHEN observing content THEN proper states are shown")
@Test @Test
fun GIVEN_loading_then_data_WHEN_observing_content_THEN_proper_states_are_shown() { fun loadingThenLoadedDataResultsInProperUIStates() {
whenever(mockGetAllContentUseCase.get()).doReturn(flowOf(Resource.Loading(), Resource.Success(emptyList()))) whenever(mockGetAllContentUseCase.get()).doReturn(flowOf(Resource.Loading(), Resource.Success(emptyList())))
val errorMessageTestObserver = sut.errorMessage.test() val errorMessageTestObserver = sut.errorMessage.test()
val contentTestObserver = sut.content.test() val contentTestObserver = sut.content.test()
@ -84,14 +88,15 @@ internal class MainViewModelTest {
testDispatcher.resumeDispatcher() testDispatcher.resumeDispatcher()
testDispatcher.advanceUntilIdle() testDispatcher.advanceUntilIdle()
errorMessageTestObserver.assertValueHistory(false, false, false) errorMessageTestObserver.assertValueHistory(false)
contentTestObserver.assertValueHistory(listOf()) contentTestObserver.assertValueHistory(listOf())
loadingTestObserver.assertValueHistory(true, false) loadingTestObserver.assertValueHistory(true, false)
sut.navigateToAuth.test().assertNoValue() sut.navigateToAuth.test().assertNoValue()
} }
@DisplayName("GIVEN loading then error WHEN observing content THEN proper states are shown")
@Test @Test
fun GIVEN_loading_then_error_WHEN_observing_content_THEN_proper_states_are_shown() { fun loadingThenErrorResultsInProperUIStates() {
whenever(mockGetAllContentUseCase.get()).doReturn(flowOf(Resource.Loading(), Resource.Error(Throwable()))) whenever(mockGetAllContentUseCase.get()).doReturn(flowOf(Resource.Loading(), Resource.Error(Throwable())))
val errorMessageTestObserver = sut.errorMessage.test() val errorMessageTestObserver = sut.errorMessage.test()
val contentTestObserver = sut.content.test() val contentTestObserver = sut.content.test()
@ -99,14 +104,15 @@ internal class MainViewModelTest {
testDispatcher.resumeDispatcher() testDispatcher.resumeDispatcher()
testDispatcher.advanceUntilIdle() testDispatcher.advanceUntilIdle()
errorMessageTestObserver.assertValueHistory(false, false, true) errorMessageTestObserver.assertValueHistory(false, true)
contentTestObserver.assertValueHistory(emptyList()) contentTestObserver.assertValueHistory(emptyList())
loadingTestObserver.assertValueHistory(true, false) loadingTestObserver.assertValueHistory(true, false)
sut.navigateToAuth.test().assertNoValue() sut.navigateToAuth.test().assertNoValue()
} }
@DisplayName("GIVEN loading then error then loading then data WHEN observing content THEN proper states are shown")
@Test @Test
fun GIVEN_loading_then_error_then_loading_then_data_WHEN_observing_content_THEN_proper_states_are_shown() { fun loadingThenErrorThenLoadingThenDataResultsInProperUIStates() {
val content = listOf( val content = listOf(
FavouriteContent(Content(ContentId(""), "", "", ImageUrl("")), false) FavouriteContent(Content(ContentId(""), "", "", ImageUrl("")), false)
) )
@ -124,14 +130,15 @@ internal class MainViewModelTest {
testDispatcher.resumeDispatcher() testDispatcher.resumeDispatcher()
testDispatcher.advanceUntilIdle() testDispatcher.advanceUntilIdle()
errorMessageTestObserver.assertValueHistory(false, false, true, false, 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() sut.navigateToAuth.test().assertNoValue()
} }
@DisplayName("GIVEN loading viewModel WHEN refreshing THEN usecase is not called")
@Test @Test
fun GIVEN_loading_viewModel_WHEN_refreshing_THEN_usecase_is_not_called() { fun fetchIsIgnoredIfViewModelIsStillLoading() {
whenever(mockGetAllContentUseCase.get()).doReturn(flowOf(Resource.Loading())) whenever(mockGetAllContentUseCase.get()).doReturn(flowOf(Resource.Loading()))
sut.content.test() sut.content.test()
testDispatcher.resumeDispatcher() testDispatcher.resumeDispatcher()
@ -143,8 +150,9 @@ internal class MainViewModelTest {
verifyZeroInteractions(mockFetchContentUseCase) verifyZeroInteractions(mockFetchContentUseCase)
} }
@DisplayName("GIVEN non loading viewModel WHEN refreshing THEN usecase is called")
@Test @Test
fun GIVEN_non_loading_viewModel_WHEN_refreshing_THEN_usecase_is_called() { fun fetchIsCalledIfViewModelIsLoaded() {
whenever(mockGetAllContentUseCase.get()).doReturn(flowOf()) whenever(mockGetAllContentUseCase.get()).doReturn(flowOf())
sut.content.test() sut.content.test()
testDispatcher.resumeDispatcher() testDispatcher.resumeDispatcher()
@ -157,8 +165,9 @@ internal class MainViewModelTest {
verifyNoMoreInteractions(mockFetchContentUseCase) verifyNoMoreInteractions(mockFetchContentUseCase)
} }
@DisplayName("GIVEN loading viewModel WHEN loging out THEN usecase is called")
@Test @Test
fun GIVEN_loading_viewModel_WHEN_loging_out_THEN_usecase_is_called() { fun loadingViewModelStillCalsLogout() {
whenever(mockGetAllContentUseCase.get()).doReturn(flowOf(Resource.Loading())) whenever(mockGetAllContentUseCase.get()).doReturn(flowOf(Resource.Loading()))
sut.content.test() sut.content.test()
testDispatcher.resumeDispatcher() testDispatcher.resumeDispatcher()
@ -171,8 +180,9 @@ internal class MainViewModelTest {
verifyNoMoreInteractions(mockLogoutUseCase) verifyNoMoreInteractions(mockLogoutUseCase)
} }
@DisplayName("GIVEN non loading viewModel WHEN loging out THEN usecase is called")
@Test @Test
fun GIVEN_non_loading_viewModel_WHEN_loging_out_THEN_usecase_is_called() { fun nonLoadingViewModelStillCalsLogout() {
whenever(mockGetAllContentUseCase.get()).doReturn(flowOf()) whenever(mockGetAllContentUseCase.get()).doReturn(flowOf())
sut.content.test() sut.content.test()
testDispatcher.resumeDispatcher() testDispatcher.resumeDispatcher()
@ -185,8 +195,9 @@ internal class MainViewModelTest {
verifyNoMoreInteractions(mockLogoutUseCase) verifyNoMoreInteractions(mockLogoutUseCase)
} }
@DisplayName("GIVEN success content list viewModel WHEN toggling a nonexistent contentId THEN nothing happens")
@Test @Test
fun GIVEN_success_content_list_viewModel_WHEN_toggling_a_nonexistent_contentId_THEN_nothing_happens() { fun interactionWithNonExistentContentIdIsIgnored() {
val contents = listOf( val contents = listOf(
FavouriteContent(Content(ContentId("a"), "", "", ImageUrl("")), false), FavouriteContent(Content(ContentId("a"), "", "", ImageUrl("")), false),
FavouriteContent(Content(ContentId("b"), "", "", ImageUrl("")), true) FavouriteContent(Content(ContentId("b"), "", "", ImageUrl("")), true)
@ -203,8 +214,9 @@ internal class MainViewModelTest {
verifyZeroInteractions(mockAddContentToFavouriteUseCase) verifyZeroInteractions(mockAddContentToFavouriteUseCase)
} }
@DisplayName("GIVEN success content list viewModel WHEN toggling a favourite contentId THEN remove favourite usecase is called")
@Test @Test
fun GIVEN_success_content_list_viewModel_WHEN_toggling_a_favourite_contentId_THEN_remove_favourite_usecase_is_called() { fun togglingFavouriteContentCallsRemoveFromFavourite() {
val contents = listOf( val contents = listOf(
FavouriteContent(Content(ContentId("a"), "", "", ImageUrl("")), false), FavouriteContent(Content(ContentId("a"), "", "", ImageUrl("")), false),
FavouriteContent(Content(ContentId("b"), "", "", ImageUrl("")), true) FavouriteContent(Content(ContentId("b"), "", "", ImageUrl("")), true)
@ -222,8 +234,9 @@ internal class MainViewModelTest {
verifyZeroInteractions(mockAddContentToFavouriteUseCase) verifyZeroInteractions(mockAddContentToFavouriteUseCase)
} }
@DisplayName("GIVEN success content list viewModel WHEN toggling a not favourite contentId THEN add favourite usecase is called")
@Test @Test
fun GIVEN_success_content_list_viewModel_WHEN_toggling_a_not_favourite_contentId_THEN_add_favourite_usecase_is_called() { fun togglingNonFavouriteContentCallsAddToFavourite() {
val contents = listOf( val contents = listOf(
FavouriteContent(Content(ContentId("a"), "", "", ImageUrl("")), false), FavouriteContent(Content(ContentId("a"), "", "", ImageUrl("")), false),
FavouriteContent(Content(ContentId("b"), "", "", ImageUrl("")), true) FavouriteContent(Content(ContentId("b"), "", "", ImageUrl("")), true)

View file

@ -1,13 +1,15 @@
package org.fnives.test.showcase.ui.shared package org.fnives.test.showcase.ui.shared
import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
@Suppress("TestFunctionName") @Suppress("TestFunctionName")
internal class EventTest { internal class EventTest {
@DisplayName("GIVEN event WHEN consumed is called THEN value is returned")
@Test @Test
fun GIVEN_event_WHEN_consumed_is_called_THEN_value_is_returned() { fun consumedReturnsValue() {
val expected = "a" val expected = "a"
val actual = Event("a").consume() val actual = Event("a").consume()
@ -15,8 +17,9 @@ internal class EventTest {
Assertions.assertEquals(expected, actual) Assertions.assertEquals(expected, actual)
} }
@DisplayName("GIVEN consumed event WHEN consumed is called THEN null is returned")
@Test @Test
fun GIVEN_consumed_event_WHEN_consumed_is_called_THEN_null_is_returned() { fun consumedEventReturnsNull() {
val expected: String? = null val expected: String? = null
val event = Event("a") val event = Event("a")
event.consume() event.consume()
@ -26,8 +29,9 @@ internal class EventTest {
Assertions.assertEquals(expected, actual) Assertions.assertEquals(expected, actual)
} }
@DisplayName("GIVEN event WHEN peek is called THEN value is returned")
@Test @Test
fun GIVEN_event_WHEN_peek_is_called_THEN_value_is_returned() { fun peekReturnsValue() {
val expected = "a" val expected = "a"
val actual = Event("a").peek() val actual = Event("a").peek()
@ -35,8 +39,9 @@ internal class EventTest {
Assertions.assertEquals(expected, actual) Assertions.assertEquals(expected, actual)
} }
@DisplayName("GIVEN consumed event WHEN peek is called THEN value is returned")
@Test @Test
fun GIVEN_consumed_event_WHEN_peek_is_called_THEN_value_is_returned() { fun consumedEventPeekedReturnsValue() {
val expected = "a" val expected = "a"
val event = Event("a") val event = Event("a")
event.consume() event.consume()

View file

@ -28,13 +28,13 @@ internal class AddContentToFavouriteUseCaseTest {
sut = AddContentToFavouriteUseCase(mockFavouriteContentLocalStorage) sut = AddContentToFavouriteUseCase(mockFavouriteContentLocalStorage)
} }
@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) verifyZeroInteractions(mockFavouriteContentLocalStorage)
} }
@DisplayName("GIVEN_contentId_WHEN_called_THEN_storage_is_called") @DisplayName("GIVEN contentId WHEN called THEN storage is called")
@Test @Test
fun contentIdIsDelegatedToStorage() = runBlockingTest { fun contentIdIsDelegatedToStorage() = runBlockingTest {
sut.invoke(ContentId("a")) sut.invoke(ContentId("a"))
@ -43,7 +43,7 @@ internal class AddContentToFavouriteUseCaseTest {
verifyNoMoreInteractions(mockFavouriteContentLocalStorage) verifyNoMoreInteractions(mockFavouriteContentLocalStorage)
} }
@DisplayName("GIVEN_throwing_local_storage_WHEN_thrown_THEN_its_propagated") @DisplayName("GIVEN throwing local storage WHEN thrown THEN its propagated")
@Test @Test
fun storageThrowingIsPropagated() = runBlockingTest { fun storageThrowingIsPropagated() = runBlockingTest {
whenever(mockFavouriteContentLocalStorage.markAsFavourite(ContentId("a"))).doThrow( whenever(mockFavouriteContentLocalStorage.markAsFavourite(ContentId("a"))).doThrow(

View file

@ -35,7 +35,7 @@ class CodeKataLoginRemoteSourceTest {
fun badRequestMeansInvalidCredentials() = runBlocking { fun badRequestMeansInvalidCredentials() = runBlocking {
} }
@DisplayName("GIVEN_internal_error_response_WHEN_request_is_fired_THEN_network_exception_is_thrown") @DisplayName("GIVEN internal error response WHEN request is fired THEN network exception is thrown")
@Test @Test
fun genericErrorMeansNetworkError() { fun genericErrorMeansNetworkError() {
} }

View file

@ -42,7 +42,7 @@ class LoginRemoteSourceRefreshActionImplTest {
.inject(this) .inject(this)
} }
@DisplayName("GIVEN_successful_response_WHEN_refresh_request_is_fired_THEN_session_is_returned") @DisplayName("GIVEN successful response WHEN refresh request is fired THEN session is returned")
@Test @Test
fun successResponseResultsInSession() = runBlocking { fun successResponseResultsInSession() = runBlocking {
mockServerScenarioSetup.setScenario(RefreshTokenScenario.Success) mockServerScenarioSetup.setScenario(RefreshTokenScenario.Success)
@ -53,7 +53,7 @@ class LoginRemoteSourceRefreshActionImplTest {
Assertions.assertEquals(expected, actual) Assertions.assertEquals(expected, actual)
} }
@DisplayName("GIVEN_successful_response_WHEN_refresh_request_is_fired_THEN_the_request_is_setup_properly") @DisplayName("GIVEN successful response WHEN refresh request is fired THEN the request is setup properly")
@Test @Test
fun refreshRequestIsSetupProperly() = runBlocking { fun refreshRequestIsSetupProperly() = runBlocking {
mockServerScenarioSetup.setScenario(RefreshTokenScenario.Success, false) mockServerScenarioSetup.setScenario(RefreshTokenScenario.Success, false)
@ -71,7 +71,7 @@ class LoginRemoteSourceRefreshActionImplTest {
Assertions.assertEquals("", request.body.readUtf8()) Assertions.assertEquals("", request.body.readUtf8())
} }
@DisplayName("GIVEN_internal_error_response_WHEN_refresh_request_is_fired_THEN_network_exception_is_thrown") @DisplayName("GIVEN internal error response WHEN refresh request is fired THEN network exception is thrown")
@Test @Test
fun generalErrorResponseResultsInNetworkException() { fun generalErrorResponseResultsInNetworkException() {
mockServerScenarioSetup.setScenario(RefreshTokenScenario.Error) mockServerScenarioSetup.setScenario(RefreshTokenScenario.Error)
@ -81,7 +81,7 @@ class LoginRemoteSourceRefreshActionImplTest {
} }
} }
@DisplayName("GIVEN_invalid_json_response_WHEN_refresh_request_is_fired_THEN_network_exception_is_thrown") @DisplayName("GIVEN invalid json response WHEN refresh request is fired THEN network exception is thrown")
@Test @Test
fun jsonErrorResponseResultsInParsingException() { fun jsonErrorResponseResultsInParsingException() {
mockServerScenarioSetup.setScenario(RefreshTokenScenario.UnexpectedJsonAsSuccessResponse) mockServerScenarioSetup.setScenario(RefreshTokenScenario.UnexpectedJsonAsSuccessResponse)
@ -91,7 +91,7 @@ class LoginRemoteSourceRefreshActionImplTest {
} }
} }
@DisplayName("GIVEN_malformed_json_response_WHEN_refresh_request_is_fired_THEN_parsing_exception_is_thrown") @DisplayName("GIVEN malformed json response WHEN refresh request is fired THEN parsing exception is thrown")
@Test @Test
fun malformedJsonErrorResponseResultsInParsingException() { fun malformedJsonErrorResponseResultsInParsingException() {
mockServerScenarioSetup.setScenario(RefreshTokenScenario.MalformedJson) mockServerScenarioSetup.setScenario(RefreshTokenScenario.MalformedJson)

View file

@ -88,7 +88,7 @@ class LoginRemoteSourceTest {
Assertions.assertEquals(expected, actual) Assertions.assertEquals(expected, actual)
} }
@DisplayName("GIVEN_internal_error_response_WHEN_request_is_fired_THEN_network_exception_is_thrown") @DisplayName("GIVEN internal error response WHEN request is fired THEN network exception is thrown")
@Test @Test
fun genericErrorMeansNetworkError() { fun genericErrorMeansNetworkError() {
mockServerScenarioSetup.setScenario(AuthScenario.GenericError("a", "b")) mockServerScenarioSetup.setScenario(AuthScenario.GenericError("a", "b"))

View file

@ -54,7 +54,7 @@ class LoginRemoteSourceRefreshActionImplTest : KoinTest {
stopKoin() stopKoin()
} }
@DisplayName("GIVEN_successful_response_WHEN_refresh_request_is_fired_THEN_session_is_returned") @DisplayName("GIVEN successful response WHEN refresh request is fired THEN session is returned")
@Test @Test
fun successResponseResultsInSession() = runBlocking { fun successResponseResultsInSession() = runBlocking {
mockServerScenarioSetup.setScenario(RefreshTokenScenario.Success) mockServerScenarioSetup.setScenario(RefreshTokenScenario.Success)
@ -65,7 +65,7 @@ class LoginRemoteSourceRefreshActionImplTest : KoinTest {
Assertions.assertEquals(expected, actual) Assertions.assertEquals(expected, actual)
} }
@DisplayName("GIVEN_successful_response_WHEN_refresh_request_is_fired_THEN_the_request_is_setup_properly") @DisplayName("GIVEN successful response WHEN refresh request is fired THEN the request is setup properly")
@Test @Test
fun refreshRequestIsSetupProperly() = runBlocking { fun refreshRequestIsSetupProperly() = runBlocking {
mockServerScenarioSetup.setScenario(RefreshTokenScenario.Success, false) mockServerScenarioSetup.setScenario(RefreshTokenScenario.Success, false)
@ -80,7 +80,7 @@ class LoginRemoteSourceRefreshActionImplTest : KoinTest {
Assertions.assertEquals("", request.body.readUtf8()) Assertions.assertEquals("", request.body.readUtf8())
} }
@DisplayName("GIVEN_internal_error_response_WHEN_refresh_request_is_fired_THEN_network_exception_is_thrown") @DisplayName("GIVEN internal error response WHEN refresh request is fired THEN network exception is thrown")
@Test @Test
fun generalErrorResponseResultsInNetworkException() { fun generalErrorResponseResultsInNetworkException() {
mockServerScenarioSetup.setScenario(RefreshTokenScenario.Error) mockServerScenarioSetup.setScenario(RefreshTokenScenario.Error)
@ -90,7 +90,7 @@ class LoginRemoteSourceRefreshActionImplTest : KoinTest {
} }
} }
@DisplayName("GIVEN_invalid_json_response_WHEN_refresh_request_is_fired_THEN_network_exception_is_thrown") @DisplayName("GIVEN invalid json response WHEN refresh request is fired THEN network exception is thrown")
@Test @Test
fun jsonErrorResponseResultsInParsingException() { fun jsonErrorResponseResultsInParsingException() {
mockServerScenarioSetup.setScenario(RefreshTokenScenario.UnexpectedJsonAsSuccessResponse) mockServerScenarioSetup.setScenario(RefreshTokenScenario.UnexpectedJsonAsSuccessResponse)
@ -100,7 +100,7 @@ class LoginRemoteSourceRefreshActionImplTest : KoinTest {
} }
} }
@DisplayName("GIVEN_malformed_json_response_WHEN_refresh_request_is_fired_THEN_parsing_exception_is_thrown") @DisplayName("GIVEN malformed json response WHEN refresh request is fired THEN parsing exception is thrown")
@Test @Test
fun malformedJsonErrorResponseResultsInParsingException() { fun malformedJsonErrorResponseResultsInParsingException() {
mockServerScenarioSetup.setScenario(RefreshTokenScenario.MalformedJson) mockServerScenarioSetup.setScenario(RefreshTokenScenario.MalformedJson)

View file

@ -100,7 +100,7 @@ class LoginRemoteSourceTest : KoinTest {
Assertions.assertEquals(expected, actual) Assertions.assertEquals(expected, actual)
} }
@DisplayName("GIVEN_internal_error_response_WHEN_request_is_fired_THEN_network_exception_is_thrown") @DisplayName("GIVEN internal error response WHEN request is fired THEN network exception is thrown")
@Test @Test
fun genericErrorMeansNetworkError() { fun genericErrorMeansNetworkError() {
mockServerScenarioSetup.setScenario(AuthScenario.GenericError("a", "b")) mockServerScenarioSetup.setScenario(AuthScenario.GenericError("a", "b"))

View file

@ -49,7 +49,7 @@ class CodeKataSessionExpirationTest : KoinTest {
mockWebServer.shutdown() mockWebServer.shutdown()
} }
@DisplayName("GIVEN_401_THEN_refresh_token_ok_response_WHEN_content_requested_THE_tokens_are_refreshed_and_request_retried_with_new_tokens") @DisplayName("GIVEN 401 THEN refresh token ok response WHEN content requested THE tokens are refreshed and request retried with new tokens")
@Test @Test
fun successRefreshResultsInRequestRetry() = runBlocking { fun successRefreshResultsInRequestRetry() = runBlocking {
} }

View file

@ -55,7 +55,7 @@ class SessionExpirationTest {
.inject(this) .inject(this)
} }
@DisplayName("GIVEN_401_THEN_refresh_token_ok_response_WHEN_content_requested_THE_tokens_are_refreshed_and_request_retried_with_new_tokens") @DisplayName("GIVEN 401 THEN refresh token ok response WHEN content requested THE tokens are refreshed and request retried with new tokens")
@Test @Test
fun successRefreshResultsInRequestRetry() = runBlocking { fun successRefreshResultsInRequestRetry() = runBlocking {
var sessionToReturnByMock: Session? = ContentData.loginSuccessResponse var sessionToReturnByMock: Session? = ContentData.loginSuccessResponse

View file

@ -66,7 +66,7 @@ class SessionExpirationTest : KoinTest {
stopKoin() stopKoin()
} }
@DisplayName("GIVEN_401_THEN_refresh_token_ok_response_WHEN_content_requested_THE_tokens_are_refreshed_and_request_retried_with_new_tokens") @DisplayName("GIVEN 401 THEN refresh token ok response WHEN content requested THE tokens are refreshed and request retried with new tokens")
@Test @Test
fun successRefreshResultsInRequestRetry() = runBlocking { fun successRefreshResultsInRequestRetry() = runBlocking {
var sessionToReturnByMock: Session? = ContentData.loginSuccessResponse var sessionToReturnByMock: Session? = ContentData.loginSuccessResponse