core description
This commit is contained in:
parent
878eff1f59
commit
978b1f6575
8 changed files with 849 additions and 100 deletions
|
|
@ -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() {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
@ -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")))
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
mock-maker-inline
|
||||
#mock-maker-inline
|
||||
Loading…
Add table
Add a link
Reference in a new issue