core description

This commit is contained in:
Gergely Hegedus 2021-04-19 23:01:16 +03:00
parent 878eff1f59
commit 978b1f6575
8 changed files with 849 additions and 100 deletions

View file

@ -0,0 +1,77 @@
package org.fnives.test.showcase.core.content
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.async
import kotlinx.coroutines.flow.take
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.test.TestCoroutineDispatcher
import kotlinx.coroutines.test.runBlockingTest
import org.fnives.test.showcase.core.shared.UnexpectedException
import org.fnives.test.showcase.model.content.Content
import org.fnives.test.showcase.model.content.ContentId
import org.fnives.test.showcase.model.content.ImageUrl
import org.fnives.test.showcase.model.shared.Resource
import org.fnives.test.showcase.network.content.ContentRemoteSource
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.mockito.kotlin.doAnswer
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.doSuspendableAnswer
import org.mockito.kotlin.doThrow
import org.mockito.kotlin.mock
import org.mockito.kotlin.times
import org.mockito.kotlin.verify
import org.mockito.kotlin.verifyNoMoreInteractions
import org.mockito.kotlin.whenever
class CodeKataContentRepositoryTest {
@BeforeEach
fun setUp() {
}
@DisplayName("GIVEN no interaction THEN remote source is not called")
@Test
fun fetchingIsLazy() {
}
@DisplayName("GIVEN content response WHEN content observed THEN loading AND data is returned")
@Test
fun happyFlow() = runBlockingTest {
}
@DisplayName("GIVEN content error WHEN content observed THEN loading AND data is returned")
@Test
fun errorFlow() = runBlockingTest {
}
@DisplayName("GIVEN saved cache WHEN collected THEN cache is returned")
@Test
fun verifyCaching() = runBlockingTest {
}
@DisplayName("GIVEN no response from remote source WHEN content observed THEN loading is returned")
@Test
fun loadingIsShownBeforeTheRequestIsReturned() = runBlockingTest {
}
@DisplayName("GIVEN content response THEN error WHEN fetched THEN returned states are loading data loading error")
@Test
fun whenFetchingRequestIsCalledAgain() = runBlockingTest {
}
@DisplayName("GIVEN content response THEN error WHEN fetched THEN only 4 items are emitted")
@Test
fun noAdditionalItemsEmitted() {
}
}

View file

@ -14,16 +14,9 @@ import org.fnives.test.showcase.model.shared.Resource
import org.fnives.test.showcase.network.content.ContentRemoteSource
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.mockito.kotlin.doAnswer
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.doSuspendableAnswer
import org.mockito.kotlin.doThrow
import org.mockito.kotlin.mock
import org.mockito.kotlin.times
import org.mockito.kotlin.verify
import org.mockito.kotlin.verifyNoMoreInteractions
import org.mockito.kotlin.whenever
import org.mockito.kotlin.*
@Suppress("TestFunctionName")
internal class ContentRepositoryTest {
@ -35,93 +28,111 @@ internal class ContentRepositoryTest {
@BeforeEach
fun setUp() {
testDispatcher = TestCoroutineDispatcher()
testDispatcher.pauseDispatcher()
mockContentRemoteSource = mock()
sut = ContentRepository(mockContentRemoteSource)
}
@DisplayName("GIVEN no interaction THEN remote source is not called")
@Test
fun GIVEN_no_interaction_THEN_remote_source_is_not_called() {
fun fetchingIsLazy() {
verifyNoMoreInteractions(mockContentRemoteSource)
}
@DisplayName("GIVEN content response WHEN content observed THEN loading AND data is returned")
@Test
fun GIVEN_no_response_from_remote_source_WHEN_content_observed_THEN_loading_is_returned() =
runBlockingTest(testDispatcher) {
val expected = Resource.Loading<List<Content>>()
val suspendedRequest = CompletableDeferred<Unit>()
whenever(mockContentRemoteSource.get()).doSuspendableAnswer {
suspendedRequest.await()
emptyList()
}
val actual = sut.contents.take(1).toList()
Assertions.assertEquals(listOf(expected), actual)
suspendedRequest.complete(Unit)
}
@Test
fun GIVEN_content_response_WHEN_content_observed_THEN_loading_AND_data_is_returned() =
runBlockingTest(testDispatcher) {
val expected = listOf(
fun happyFlow() = runBlockingTest {
val expected = listOf(
Resource.Loading(),
Resource.Success(listOf(Content(ContentId("a"), "", "", ImageUrl(""))))
)
whenever(mockContentRemoteSource.get())
.doReturn(listOf(Content(ContentId("a"), "", "", ImageUrl(""))))
)
whenever(mockContentRemoteSource.get()).doReturn(listOf(Content(ContentId("a"), "", "", ImageUrl(""))))
val actual = sut.contents.take(2).toList()
val actual = sut.contents.take(2).toList()
Assertions.assertEquals(expected, actual)
}
Assertions.assertEquals(expected, actual)
}
@DisplayName("GIVEN content error WHEN content observed THEN loading AND data is returned")
@Test
fun GIVEN_content_error_WHEN_content_observed_THEN_loading_AND_data_is_returned() =
runBlockingTest(testDispatcher) {
val exception = RuntimeException()
val expected = listOf(
fun errorFlow() = runBlockingTest {
val exception = RuntimeException()
val expected = listOf(
Resource.Loading(),
Resource.Error<List<Content>>(UnexpectedException(exception))
)
whenever(mockContentRemoteSource.get()).doThrow(exception)
)
whenever(mockContentRemoteSource.get()).doThrow(exception)
val actual = sut.contents.take(2).toList()
val actual = sut.contents.take(2).toList()
Assertions.assertEquals(expected, actual)
Assertions.assertEquals(expected, actual)
}
@DisplayName("GIVEN saved cache WHEN collected THEN cache is returned")
@Test
fun verifyCaching() = runBlockingTest {
val content = Content(ContentId("1"), "", "", ImageUrl(""))
val expected = listOf(Resource.Success(listOf(content)))
whenever(mockContentRemoteSource.get()).doReturn(listOf(content))
sut.contents.take(2).toList()
val actual = sut.contents.take(1).toList()
verify(mockContentRemoteSource, times(1)).get()
Assertions.assertEquals(expected, actual)
}
@DisplayName("GIVEN no response from remote source WHEN content observed THEN loading is returned")
@Test
fun loadingIsShownBeforeTheRequestIsReturned() = runBlockingTest {
val expected = Resource.Loading<List<Content>>()
val suspendedRequest = CompletableDeferred<Unit>()
whenever(mockContentRemoteSource.get()).doSuspendableAnswer {
suspendedRequest.await()
emptyList()
}
val actual = sut.contents.take(1).toList()
Assertions.assertEquals(listOf(expected), actual)
suspendedRequest.complete(Unit)
}
@DisplayName("GIVEN content response THEN error WHEN fetched THEN returned states are loading data loading error")
@Test
fun GIVEN_content_response_THEN_error_WHEN_fetched_THEN_returned_states_are_loading_data_loading_error() =
runBlockingTest(testDispatcher) {
val exception = RuntimeException()
val expected = listOf(
Resource.Loading(),
Resource.Success(emptyList()),
Resource.Loading(),
Resource.Error<List<Content>>(UnexpectedException(exception))
)
var first = true
whenever(mockContentRemoteSource.get()).doAnswer {
if (first) emptyList<Content>().also { first = false } else throw exception
fun whenFetchingRequestIsCalledAgain() =
runBlockingTest(testDispatcher) {
val exception = RuntimeException()
val expected = listOf(
Resource.Loading(),
Resource.Success(emptyList()),
Resource.Loading(),
Resource.Error<List<Content>>(UnexpectedException(exception))
)
var first = true
whenever(mockContentRemoteSource.get()).doAnswer {
if (first) emptyList<Content>().also { first = false } else throw exception
}
val actual = async(testDispatcher) { sut.contents.take(4).toList() }
testDispatcher.advanceUntilIdle()
sut.fetch()
testDispatcher.advanceUntilIdle()
Assertions.assertEquals(expected, actual.await())
}
val actual = async(testDispatcher) { sut.contents.take(4).toList() }
testDispatcher.advanceUntilIdle()
sut.fetch()
testDispatcher.advanceUntilIdle()
Assertions.assertEquals(expected, actual.await())
}
@DisplayName("GIVEN content response THEN error WHEN fetched THEN only 4 items are emitted")
@Test
fun GIVEN_content_response_THEN_error_WHEN_fetched_THEN_only_4_items_are_emitted() {
fun noAdditionalItemsEmitted() {
Assertions.assertThrows(IllegalStateException::class.java) {
runBlockingTest(testDispatcher) {
val exception = RuntimeException()
val expected = listOf(
Resource.Loading(),
Resource.Success(emptyList()),
Resource.Loading(),
Resource.Error<List<Content>>(UnexpectedException(exception))
Resource.Loading(),
Resource.Success(emptyList()),
Resource.Loading(),
Resource.Error<List<Content>>(UnexpectedException(exception))
)
var first = true
whenever(mockContentRemoteSource.get()).doAnswer {
@ -137,17 +148,4 @@ internal class ContentRepositoryTest {
}
}
}
@Test
fun GIVEN_saved_cache_WHEN_collected_THEN_cache_is_returned() = runBlockingTest {
val content = Content(ContentId("1"), "", "", ImageUrl(""))
val expected = listOf(Resource.Success(listOf(content)))
whenever(mockContentRemoteSource.get()).doReturn(listOf(content))
sut.contents.take(2).toList()
val actual = sut.contents.take(1).toList()
verify(mockContentRemoteSource, times(1)).get()
Assertions.assertEquals(expected, actual)
}
}

View file

@ -0,0 +1,54 @@
package org.fnives.test.showcase.core.login
import kotlinx.coroutines.test.runBlockingTest
import org.fnives.test.showcase.core.shared.UnexpectedException
import org.fnives.test.showcase.core.storage.UserDataLocalStorage
import org.fnives.test.showcase.model.auth.LoginCredentials
import org.fnives.test.showcase.model.auth.LoginStatus
import org.fnives.test.showcase.model.session.Session
import org.fnives.test.showcase.model.shared.Answer
import org.fnives.test.showcase.network.auth.LoginRemoteSource
import org.fnives.test.showcase.network.auth.model.LoginStatusResponses
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.mockito.kotlin.*
class CodeKataSecondLoginUseCaseTest {
@BeforeEach
fun setUp() {
TODO()
}
@DisplayName("GIVEN empty username WHEN trying to login THEN invalid username is returned")
@Test
fun emptyUserNameReturnsLoginStatusError() {
TODO()
}
@DisplayName("GIVEN empty password WHEN trying to login THEN invalid password is returned")
@Test
fun emptyPasswordNameReturnsLoginStatusError() {
TODO()
}
@DisplayName("GIVEN invalid credentials response WHEN trying to login THEN invalid credentials is returned ")
@Test
fun invalidLoginResponseReturnInvalidCredentials() {
TODO()
}
@DisplayName("GIVEN success response WHEN trying to login THEN session is saved and success is returned")
@Test
fun validResponseResultsInSavingSessionAndSuccessReturned() {
TODO()
}
@DisplayName("GIVEN error resposne WHEN trying to login THEN session is not touched and error is returned")
@Test
fun invalidResponseResultsInErrorReturned() {
TODO()
}
}

View file

@ -11,14 +11,10 @@ import org.fnives.test.showcase.network.auth.LoginRemoteSource
import org.fnives.test.showcase.network.auth.model.LoginStatusResponses
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.doThrow
import org.mockito.kotlin.mock
import org.mockito.kotlin.times
import org.mockito.kotlin.verify
import org.mockito.kotlin.verifyZeroInteractions
import org.mockito.kotlin.whenever
import org.mockito.kotlin.*
import java.util.stream.Stream
@Suppress("TestFunctionName")
internal class LoginUseCaseTest {
@ -34,8 +30,9 @@ internal class LoginUseCaseTest {
sut = LoginUseCase(mockLoginRemoteSource, mockUserDataLocalStorage)
}
@DisplayName("GIVEN empty username WHEN trying to login THEN invalid username is returned")
@Test
fun GIVEN_empty_username_WHEN_trying_to_login_THEN_invalid_username_is_returned() = runBlockingTest {
fun emptyUserNameReturnsLoginStatusError() = runBlockingTest {
val expected = Answer.Success(LoginStatus.INVALID_USERNAME)
val actual = sut.invoke(LoginCredentials("", "a"))
@ -45,8 +42,9 @@ internal class LoginUseCaseTest {
verifyZeroInteractions(mockUserDataLocalStorage)
}
@DisplayName("GIVEN empty password WHEN trying to login THEN invalid password is returned")
@Test
fun GIVEN_empty_password_WHEN_trying_to_login_THEN_invalid_password_is_returned() = runBlockingTest {
fun emptyPasswordNameReturnsLoginStatusError() = runBlockingTest {
val expected = Answer.Success(LoginStatus.INVALID_PASSWORD)
val actual = sut.invoke(LoginCredentials("a", ""))
@ -56,8 +54,9 @@ internal class LoginUseCaseTest {
verifyZeroInteractions(mockUserDataLocalStorage)
}
@DisplayName("GIVEN invalid credentials response WHEN trying to login THEN invalid credentials is returned ")
@Test
fun GIVEN_login_invalid_credentials_response_WHEN_trying_to_login_THEN_invalid_credentials_is_returned() = runBlockingTest {
fun invalidLoginResponseReturnInvalidCredentials() = runBlockingTest {
val expected = Answer.Success(LoginStatus.INVALID_CREDENTIALS)
whenever(mockLoginRemoteSource.login(LoginCredentials("a", "b")))
.doReturn(LoginStatusResponses.InvalidCredentials)
@ -68,8 +67,9 @@ internal class LoginUseCaseTest {
verifyZeroInteractions(mockUserDataLocalStorage)
}
@DisplayName("GIVEN success response WHEN trying to login THEN session is saved and success is returned")
@Test
fun GIVEN_valid_login_response_WHEN_trying_to_login_THEN_Success_is_returned() = runBlockingTest {
fun validResponseResultsInSavingSessionAndSuccessReturned() = runBlockingTest {
val expected = Answer.Success(LoginStatus.SUCCESS)
whenever(mockLoginRemoteSource.login(LoginCredentials("a", "b")))
.doReturn(LoginStatusResponses.Success(Session("c", "d")))
@ -78,10 +78,12 @@ internal class LoginUseCaseTest {
Assertions.assertEquals(expected, actual)
verify(mockUserDataLocalStorage, times(1)).session = Session("c", "d")
verifyNoMoreInteractions(mockUserDataLocalStorage)
}
@DisplayName("GIVEN error resposne WHEN trying to login THEN session is not touched and error is returned")
@Test
fun GIVEN_throwing_remote_source_WHEN_trying_to_login_THEN_error_is_returned() = runBlockingTest {
fun invalidResponseResultsInErrorReturned() = runBlockingTest {
val exception = RuntimeException()
val expected = Answer.Error<LoginStatus>(UnexpectedException(exception))
whenever(mockLoginRemoteSource.login(LoginCredentials("a", "b")))

View file

@ -0,0 +1,10 @@
package org.fnives.test.showcase.core.session
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.mockito.kotlin.*
class CodeKataFirstSessionExpirationAdapterTest {
}

View file

@ -1,6 +1,7 @@
package org.fnives.test.showcase.core.session
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.mockito.kotlin.mock
import org.mockito.kotlin.times
@ -20,16 +21,18 @@ internal class SessionExpirationAdapterTest {
sut = SessionExpirationAdapter(mockSessionExpirationListener)
}
@DisplayName("WHEN nothing is changed THEN delegate is not touched")
@Test
fun WHEN_onSessionExpired_is_called_THEN_its_delegated() {
fun verifyNoInteractionsIfNoInvocations() {
verifyZeroInteractions(mockSessionExpirationListener)
}
@DisplayName("WHEN onSessionExpired is called THEN delegated is also called")
@Test
fun verifyOnSessionExpirationIsDelegated() {
sut.onSessionExpired()
verify(mockSessionExpirationListener, times(1)).onSessionExpired()
verifyNoMoreInteractions(mockSessionExpirationListener)
}
@Test
fun WHEN_nothing_is_changed_THEN_delegate_is_not_touched() {
verifyZeroInteractions(mockSessionExpirationListener)
}
}

View file

@ -1 +1 @@
mock-maker-inline
#mock-maker-inline