Merge "Update Main dispatcher rule, assert on StateFlow's value property" into main

pull/152/head
Jolanda Verhoef 2 years ago committed by Gerrit Code Review
commit 70806f6104

@ -16,31 +16,27 @@
package com.google.samples.apps.nowinandroid.core.testing.util package com.google.samples.apps.nowinandroid.core.testing.util
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.TestDispatcher
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.resetMain import kotlinx.coroutines.test.resetMain
import kotlinx.coroutines.test.setMain import kotlinx.coroutines.test.setMain
import org.junit.rules.TestRule import org.junit.rules.TestRule
import org.junit.rules.TestWatcher
import org.junit.runner.Description import org.junit.runner.Description
import org.junit.runners.model.Statement
/** /**
* A [TestRule] that initializes the main dispatcher to [dispatcher], which defaults to a * A JUnit [TestRule] that sets the Main dispatcher to [testDispatcher]
* [StandardTestDispatcher]. * for the duration of the test.
*/ */
class TestDispatcherRule( class MainDispatcherRule(
private val dispatcher: CoroutineDispatcher = StandardTestDispatcher() val testDispatcher: TestDispatcher = UnconfinedTestDispatcher(),
) : TestRule { ) : TestWatcher() {
override fun apply(base: Statement, description: Description): Statement = override fun starting(description: Description) {
object : Statement() { Dispatchers.setMain(testDispatcher)
override fun evaluate() {
Dispatchers.setMain(dispatcher)
try {
base.evaluate()
} finally {
Dispatchers.resetMain()
}
} }
override fun finished(description: Description) {
Dispatchers.resetMain()
} }
} }

@ -17,7 +17,6 @@
package com.google.samples.apps.nowinandroid.feature.author package com.google.samples.apps.nowinandroid.feature.author
import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.SavedStateHandle
import app.cash.turbine.test
import com.google.samples.apps.nowinandroid.core.model.data.Author import com.google.samples.apps.nowinandroid.core.model.data.Author
import com.google.samples.apps.nowinandroid.core.model.data.FollowableAuthor import com.google.samples.apps.nowinandroid.core.model.data.FollowableAuthor
import com.google.samples.apps.nowinandroid.core.model.data.NewsResource import com.google.samples.apps.nowinandroid.core.model.data.NewsResource
@ -25,9 +24,12 @@ import com.google.samples.apps.nowinandroid.core.model.data.NewsResourceType.Vid
import com.google.samples.apps.nowinandroid.core.testing.repository.TestAuthorsRepository import com.google.samples.apps.nowinandroid.core.testing.repository.TestAuthorsRepository
import com.google.samples.apps.nowinandroid.core.testing.repository.TestNewsRepository import com.google.samples.apps.nowinandroid.core.testing.repository.TestNewsRepository
import com.google.samples.apps.nowinandroid.core.testing.repository.TestUserDataRepository import com.google.samples.apps.nowinandroid.core.testing.repository.TestUserDataRepository
import com.google.samples.apps.nowinandroid.core.testing.util.TestDispatcherRule import com.google.samples.apps.nowinandroid.core.testing.util.MainDispatcherRule
import com.google.samples.apps.nowinandroid.feature.author.navigation.AuthorDestination import com.google.samples.apps.nowinandroid.feature.author.navigation.AuthorDestination
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import kotlinx.datetime.Instant import kotlinx.datetime.Instant
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
@ -36,10 +38,14 @@ import org.junit.Before
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
/**
* To learn more about how this test handles Flows created with stateIn, see
* https://developer.android.com/kotlin/flow/test#statein
*/
class AuthorViewModelTest { class AuthorViewModelTest {
@get:Rule @get:Rule
val dispatcherRule = TestDispatcherRule() val dispatcherRule = MainDispatcherRule()
private val userDataRepository = TestUserDataRepository() private val userDataRepository = TestUserDataRepository()
private val authorsRepository = TestAuthorsRepository() private val authorsRepository = TestAuthorsRepository()
@ -62,13 +68,13 @@ class AuthorViewModelTest {
@Test @Test
fun uiStateAuthor_whenSuccess_matchesAuthorFromRepository() = runTest { fun uiStateAuthor_whenSuccess_matchesAuthorFromRepository() = runTest {
viewModel.uiState.test { val collectJob = launch(UnconfinedTestDispatcher()) { viewModel.uiState.collect() }
awaitItem()
// To make sure AuthorUiState is success // To make sure AuthorUiState is success
authorsRepository.sendAuthors(testInputAuthors.map(FollowableAuthor::author)) authorsRepository.sendAuthors(testInputAuthors.map(FollowableAuthor::author))
userDataRepository.setFollowedAuthorIds(setOf(testInputAuthors[1].author.id)) userDataRepository.setFollowedAuthorIds(setOf(testInputAuthors[1].author.id))
val item = awaitItem() val item = viewModel.uiState.value
assertTrue(item.authorState is AuthorUiState.Success) assertTrue(item.authorState is AuthorUiState.Success)
val successAuthorUiState = item.authorState as AuthorUiState.Success val successAuthorUiState = item.authorState as AuthorUiState.Success
@ -78,63 +84,63 @@ class AuthorViewModelTest {
successAuthorUiState.followableAuthor.author successAuthorUiState.followableAuthor.author
assertEquals(authorFromRepository, successAuthorUiState.followableAuthor.author) assertEquals(authorFromRepository, successAuthorUiState.followableAuthor.author)
}
collectJob.cancel()
} }
@Test @Test
fun uiStateNews_whenInitialized_thenShowLoading() = runTest { fun uiStateNews_whenInitialized_thenShowLoading() = runTest {
viewModel.uiState.test { assertEquals(NewsUiState.Loading, viewModel.uiState.value.newsState)
assertEquals(NewsUiState.Loading, awaitItem().newsState)
}
} }
@Test @Test
fun uiStateAuthor_whenInitialized_thenShowLoading() = runTest { fun uiStateAuthor_whenInitialized_thenShowLoading() = runTest {
viewModel.uiState.test { assertEquals(AuthorUiState.Loading, viewModel.uiState.value.authorState)
assertEquals(AuthorUiState.Loading, awaitItem().authorState)
}
} }
@Test @Test
fun uiStateAuthor_whenFollowedIdsSuccessAndAuthorLoading_thenShowLoading() = runTest { fun uiStateAuthor_whenFollowedIdsSuccessAndAuthorLoading_thenShowLoading() = runTest {
viewModel.uiState.test { val collectJob = launch(UnconfinedTestDispatcher()) { viewModel.uiState.collect() }
userDataRepository.setFollowedAuthorIds(setOf(testInputAuthors[1].author.id)) userDataRepository.setFollowedAuthorIds(setOf(testInputAuthors[1].author.id))
assertEquals(AuthorUiState.Loading, awaitItem().authorState) assertEquals(AuthorUiState.Loading, viewModel.uiState.value.authorState)
}
collectJob.cancel()
} }
@Test @Test
fun uiStateAuthor_whenFollowedIdsSuccessAndAuthorSuccess_thenAuthorSuccessAndNewsLoading() = fun uiStateAuthor_whenFollowedIdsSuccessAndAuthorSuccess_thenAuthorSuccessAndNewsLoading() =
runTest { runTest {
viewModel.uiState.test { val collectJob = launch(UnconfinedTestDispatcher()) { viewModel.uiState.collect() }
awaitItem()
authorsRepository.sendAuthors(testInputAuthors.map { it.author }) authorsRepository.sendAuthors(testInputAuthors.map { it.author })
userDataRepository.setFollowedAuthorIds(setOf(testInputAuthors[1].author.id)) userDataRepository.setFollowedAuthorIds(setOf(testInputAuthors[1].author.id))
val item = awaitItem() val item = viewModel.uiState.value
assertTrue(item.authorState is AuthorUiState.Success) assertTrue(item.authorState is AuthorUiState.Success)
assertTrue(item.newsState is NewsUiState.Loading) assertTrue(item.newsState is NewsUiState.Loading)
}
collectJob.cancel()
} }
@Test @Test
fun uiStateAuthor_whenFollowedIdsSuccessAndAuthorSuccessAndNewsIsSuccess_thenAllSuccess() = fun uiStateAuthor_whenFollowedIdsSuccessAndAuthorSuccessAndNewsIsSuccess_thenAllSuccess() =
runTest { runTest {
viewModel.uiState.test { val collectJob = launch(UnconfinedTestDispatcher()) { viewModel.uiState.collect() }
awaitItem()
authorsRepository.sendAuthors(testInputAuthors.map { it.author }) authorsRepository.sendAuthors(testInputAuthors.map { it.author })
userDataRepository.setFollowedAuthorIds(setOf(testInputAuthors[1].author.id)) userDataRepository.setFollowedAuthorIds(setOf(testInputAuthors[1].author.id))
newsRepository.sendNewsResources(sampleNewsResources) newsRepository.sendNewsResources(sampleNewsResources)
val item = awaitItem() val item = viewModel.uiState.value
assertTrue(item.authorState is AuthorUiState.Success) assertTrue(item.authorState is AuthorUiState.Success)
assertTrue(item.newsState is NewsUiState.Success) assertTrue(item.newsState is NewsUiState.Success)
}
collectJob.cancel()
} }
@Test @Test
fun uiStateAuthor_whenFollowingAuthor_thenShowUpdatedAuthor() = runTest { fun uiStateAuthor_whenFollowingAuthor_thenShowUpdatedAuthor() = runTest {
viewModel.uiState val collectJob = launch(UnconfinedTestDispatcher()) { viewModel.uiState.collect() }
.test {
awaitItem()
authorsRepository.sendAuthors(testInputAuthors.map { it.author }) authorsRepository.sendAuthors(testInputAuthors.map { it.author })
// Set which author IDs are followed, not including 0. // Set which author IDs are followed, not including 0.
userDataRepository.setFollowedAuthorIds(setOf(testInputAuthors[1].author.id)) userDataRepository.setFollowedAuthorIds(setOf(testInputAuthors[1].author.id))
@ -143,9 +149,10 @@ class AuthorViewModelTest {
assertEquals( assertEquals(
AuthorUiState.Success(followableAuthor = testOutputAuthors[0]), AuthorUiState.Success(followableAuthor = testOutputAuthors[0]),
awaitItem().authorState viewModel.uiState.value.authorState
) )
}
collectJob.cancel()
} }
} }

@ -16,7 +16,6 @@
package com.google.samples.apps.nowinandroid.interests package com.google.samples.apps.nowinandroid.interests
import app.cash.turbine.test
import com.google.samples.apps.nowinandroid.core.model.data.Author import com.google.samples.apps.nowinandroid.core.model.data.Author
import com.google.samples.apps.nowinandroid.core.model.data.FollowableAuthor import com.google.samples.apps.nowinandroid.core.model.data.FollowableAuthor
import com.google.samples.apps.nowinandroid.core.model.data.FollowableTopic import com.google.samples.apps.nowinandroid.core.model.data.FollowableTopic
@ -24,19 +23,26 @@ import com.google.samples.apps.nowinandroid.core.model.data.Topic
import com.google.samples.apps.nowinandroid.core.testing.repository.TestAuthorsRepository import com.google.samples.apps.nowinandroid.core.testing.repository.TestAuthorsRepository
import com.google.samples.apps.nowinandroid.core.testing.repository.TestTopicsRepository import com.google.samples.apps.nowinandroid.core.testing.repository.TestTopicsRepository
import com.google.samples.apps.nowinandroid.core.testing.repository.TestUserDataRepository import com.google.samples.apps.nowinandroid.core.testing.repository.TestUserDataRepository
import com.google.samples.apps.nowinandroid.core.testing.util.TestDispatcherRule import com.google.samples.apps.nowinandroid.core.testing.util.MainDispatcherRule
import com.google.samples.apps.nowinandroid.feature.interests.InterestsUiState import com.google.samples.apps.nowinandroid.feature.interests.InterestsUiState
import com.google.samples.apps.nowinandroid.feature.interests.InterestsViewModel import com.google.samples.apps.nowinandroid.feature.interests.InterestsViewModel
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Before import org.junit.Before
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
/**
* To learn more about how this test handles Flows created with stateIn, see
* https://developer.android.com/kotlin/flow/test#statein
*/
class InterestsViewModelTest { class InterestsViewModelTest {
@get:Rule @get:Rule
val dispatcherRule = TestDispatcherRule() val mainDispatcherRule = MainDispatcherRule()
private val userDataRepository = TestUserDataRepository() private val userDataRepository = TestUserDataRepository()
private val authorsRepository = TestAuthorsRepository() private val authorsRepository = TestAuthorsRepository()
@ -54,35 +60,36 @@ class InterestsViewModelTest {
@Test @Test
fun uiState_whenInitialized_thenShowLoading() = runTest { fun uiState_whenInitialized_thenShowLoading() = runTest {
viewModel.uiState.test { assertEquals(InterestsUiState.Loading, viewModel.uiState.value)
assertEquals(InterestsUiState.Loading, awaitItem())
}
} }
@Test @Test
fun uiState_whenFollowedTopicsAreLoading_thenShowLoading() = runTest { fun uiState_whenFollowedTopicsAreLoading_thenShowLoading() = runTest {
viewModel.uiState.test { val collectJob = launch(UnconfinedTestDispatcher()) { viewModel.uiState.collect() }
assertEquals(InterestsUiState.Loading, awaitItem())
userDataRepository.setFollowedAuthorIds(setOf("1")) userDataRepository.setFollowedAuthorIds(setOf("1"))
userDataRepository.setFollowedTopicIds(emptySet()) userDataRepository.setFollowedTopicIds(emptySet())
} assertEquals(InterestsUiState.Loading, viewModel.uiState.value)
collectJob.cancel()
} }
@Test @Test
fun uiState_whenFollowedAuthorsAreLoading_thenShowLoading() = runTest { fun uiState_whenFollowedAuthorsAreLoading_thenShowLoading() = runTest {
viewModel.uiState.test { val collectJob = launch(UnconfinedTestDispatcher()) { viewModel.uiState.collect() }
assertEquals(InterestsUiState.Loading, awaitItem())
userDataRepository.setFollowedAuthorIds(emptySet()) userDataRepository.setFollowedAuthorIds(emptySet())
userDataRepository.setFollowedTopicIds(setOf("1")) userDataRepository.setFollowedTopicIds(setOf("1"))
} assertEquals(InterestsUiState.Loading, viewModel.uiState.value)
collectJob.cancel()
} }
@Test @Test
fun uiState_whenFollowingNewTopic_thenShowUpdatedTopics() = runTest { fun uiState_whenFollowingNewTopic_thenShowUpdatedTopics() = runTest {
val collectJob = launch(UnconfinedTestDispatcher()) { viewModel.uiState.collect() }
val toggleTopicId = testOutputTopics[1].topic.id val toggleTopicId = testOutputTopics[1].topic.id
viewModel.uiState
.test {
awaitItem()
authorsRepository.sendAuthors(emptyList()) authorsRepository.sendAuthors(emptyList())
userDataRepository.setFollowedAuthorIds(emptySet()) userDataRepository.setFollowedAuthorIds(emptySet())
topicsRepository.sendTopics(testInputTopics.map { it.topic }) topicsRepository.sendTopics(testInputTopics.map { it.topic })
@ -90,7 +97,7 @@ class InterestsViewModelTest {
assertEquals( assertEquals(
false, false,
(awaitItem() as InterestsUiState.Interests) (viewModel.uiState.value as InterestsUiState.Interests)
.topics.first { it.topic.id == toggleTopicId }.isFollowed .topics.first { it.topic.id == toggleTopicId }.isFollowed
) )
@ -101,22 +108,21 @@ class InterestsViewModelTest {
assertEquals( assertEquals(
InterestsUiState.Interests(topics = testOutputTopics, authors = emptyList()), InterestsUiState.Interests(topics = testOutputTopics, authors = emptyList()),
awaitItem() viewModel.uiState.value
) )
}
collectJob.cancel()
} }
@Test @Test
fun uiState_whenFollowingNewAuthor_thenShowUpdatedAuthors() = runTest { fun uiState_whenFollowingNewAuthor_thenShowUpdatedAuthors() = runTest {
viewModel.uiState val collectJob = launch(UnconfinedTestDispatcher()) { viewModel.uiState.collect() }
.test {
awaitItem()
authorsRepository.sendAuthors(testInputAuthors.map { it.author }) authorsRepository.sendAuthors(testInputAuthors.map { it.author })
userDataRepository.setFollowedAuthorIds(setOf(testInputAuthors[0].author.id)) userDataRepository.setFollowedAuthorIds(setOf(testInputAuthors[0].author.id))
topicsRepository.sendTopics(listOf()) topicsRepository.sendTopics(listOf())
userDataRepository.setFollowedTopicIds(setOf()) userDataRepository.setFollowedTopicIds(setOf())
awaitItem()
viewModel.followAuthor( viewModel.followAuthor(
followedAuthorId = testInputAuthors[1].author.id, followedAuthorId = testInputAuthors[1].author.id,
followed = true followed = true
@ -124,17 +130,18 @@ class InterestsViewModelTest {
assertEquals( assertEquals(
InterestsUiState.Interests(topics = emptyList(), authors = testOutputAuthors), InterestsUiState.Interests(topics = emptyList(), authors = testOutputAuthors),
awaitItem() viewModel.uiState.value
) )
}
collectJob.cancel()
} }
@Test @Test
fun uiState_whenUnfollowingTopics_thenShowUpdatedTopics() = runTest { fun uiState_whenUnfollowingTopics_thenShowUpdatedTopics() = runTest {
val collectJob = launch(UnconfinedTestDispatcher()) { viewModel.uiState.collect() }
val toggleTopicId = testOutputTopics[1].topic.id val toggleTopicId = testOutputTopics[1].topic.id
viewModel.uiState
.test {
awaitItem()
authorsRepository.sendAuthors(emptyList()) authorsRepository.sendAuthors(emptyList())
userDataRepository.setFollowedAuthorIds(emptySet()) userDataRepository.setFollowedAuthorIds(emptySet())
topicsRepository.sendTopics(testOutputTopics.map { it.topic }) topicsRepository.sendTopics(testOutputTopics.map { it.topic })
@ -144,7 +151,7 @@ class InterestsViewModelTest {
assertEquals( assertEquals(
true, true,
(awaitItem() as InterestsUiState.Interests) (viewModel.uiState.value as InterestsUiState.Interests)
.topics.first { it.topic.id == toggleTopicId }.isFollowed .topics.first { it.topic.id == toggleTopicId }.isFollowed
) )
@ -155,16 +162,16 @@ class InterestsViewModelTest {
assertEquals( assertEquals(
InterestsUiState.Interests(topics = testInputTopics, authors = emptyList()), InterestsUiState.Interests(topics = testInputTopics, authors = emptyList()),
awaitItem() viewModel.uiState.value
) )
}
collectJob.cancel()
} }
@Test @Test
fun uiState_whenUnfollowingAuthors_thenShowUpdatedAuthors() = runTest { fun uiState_whenUnfollowingAuthors_thenShowUpdatedAuthors() = runTest {
viewModel.uiState val collectJob = launch(UnconfinedTestDispatcher()) { viewModel.uiState.collect() }
.test {
awaitItem()
authorsRepository.sendAuthors(testOutputAuthors.map { it.author }) authorsRepository.sendAuthors(testOutputAuthors.map { it.author })
userDataRepository.setFollowedAuthorIds( userDataRepository.setFollowedAuthorIds(
setOf(testOutputAuthors[0].author.id, testOutputAuthors[1].author.id) setOf(testOutputAuthors[0].author.id, testOutputAuthors[1].author.id)
@ -172,7 +179,6 @@ class InterestsViewModelTest {
topicsRepository.sendTopics(listOf()) topicsRepository.sendTopics(listOf())
userDataRepository.setFollowedTopicIds(setOf()) userDataRepository.setFollowedTopicIds(setOf())
awaitItem()
viewModel.followAuthor( viewModel.followAuthor(
followedAuthorId = testOutputAuthors[1].author.id, followedAuthorId = testOutputAuthors[1].author.id,
followed = false followed = false
@ -180,9 +186,10 @@ class InterestsViewModelTest {
assertEquals( assertEquals(
InterestsUiState.Interests(topics = emptyList(), authors = testInputAuthors), InterestsUiState.Interests(topics = emptyList(), authors = testInputAuthors),
awaitItem() viewModel.uiState.value
) )
}
collectJob.cancel()
} }
} }

@ -17,7 +17,6 @@
package com.google.samples.apps.nowinandroid.feature.topic package com.google.samples.apps.nowinandroid.feature.topic
import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.SavedStateHandle
import app.cash.turbine.test
import com.google.samples.apps.nowinandroid.core.model.data.FollowableTopic import com.google.samples.apps.nowinandroid.core.model.data.FollowableTopic
import com.google.samples.apps.nowinandroid.core.model.data.NewsResource import com.google.samples.apps.nowinandroid.core.model.data.NewsResource
import com.google.samples.apps.nowinandroid.core.model.data.NewsResourceType.Video import com.google.samples.apps.nowinandroid.core.model.data.NewsResourceType.Video
@ -25,9 +24,12 @@ import com.google.samples.apps.nowinandroid.core.model.data.Topic
import com.google.samples.apps.nowinandroid.core.testing.repository.TestNewsRepository import com.google.samples.apps.nowinandroid.core.testing.repository.TestNewsRepository
import com.google.samples.apps.nowinandroid.core.testing.repository.TestTopicsRepository import com.google.samples.apps.nowinandroid.core.testing.repository.TestTopicsRepository
import com.google.samples.apps.nowinandroid.core.testing.repository.TestUserDataRepository import com.google.samples.apps.nowinandroid.core.testing.repository.TestUserDataRepository
import com.google.samples.apps.nowinandroid.core.testing.util.TestDispatcherRule import com.google.samples.apps.nowinandroid.core.testing.util.MainDispatcherRule
import com.google.samples.apps.nowinandroid.feature.topic.navigation.TopicDestination import com.google.samples.apps.nowinandroid.feature.topic.navigation.TopicDestination
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import kotlinx.datetime.Instant import kotlinx.datetime.Instant
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
@ -36,10 +38,14 @@ import org.junit.Before
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
/**
* To learn more about how this test handles Flows created with stateIn, see
* https://developer.android.com/kotlin/flow/test#statein
*/
class TopicViewModelTest { class TopicViewModelTest {
@get:Rule @get:Rule
val dispatcherRule = TestDispatcherRule() val dispatcherRule = MainDispatcherRule()
private val userDataRepository = TestUserDataRepository() private val userDataRepository = TestUserDataRepository()
private val topicsRepository = TestTopicsRepository() private val topicsRepository = TestTopicsRepository()
@ -59,11 +65,11 @@ class TopicViewModelTest {
@Test @Test
fun uiStateAuthor_whenSuccess_matchesTopicFromRepository() = runTest { fun uiStateAuthor_whenSuccess_matchesTopicFromRepository() = runTest {
viewModel.uiState.test { val collectJob = launch(UnconfinedTestDispatcher()) { viewModel.uiState.collect() }
awaitItem()
topicsRepository.sendTopics(testInputTopics.map(FollowableTopic::topic)) topicsRepository.sendTopics(testInputTopics.map(FollowableTopic::topic))
userDataRepository.setFollowedTopicIds(setOf(testInputTopics[1].topic.id)) userDataRepository.setFollowedTopicIds(setOf(testInputTopics[1].topic.id))
val item = awaitItem() val item = viewModel.uiState.value
assertTrue(item.topicState is TopicUiState.Success) assertTrue(item.topicState is TopicUiState.Success)
val successTopicState = item.topicState as TopicUiState.Success val successTopicState = item.topicState as TopicUiState.Success
@ -72,63 +78,63 @@ class TopicViewModelTest {
).first() ).first()
assertEquals(topicFromRepository, successTopicState.followableTopic.topic) assertEquals(topicFromRepository, successTopicState.followableTopic.topic)
}
collectJob.cancel()
} }
@Test @Test
fun uiStateNews_whenInitialized_thenShowLoading() = runTest { fun uiStateNews_whenInitialized_thenShowLoading() = runTest {
viewModel.uiState.test { assertEquals(NewsUiState.Loading, viewModel.uiState.value.newsState)
assertEquals(NewsUiState.Loading, awaitItem().newsState)
}
} }
@Test @Test
fun uiStateTopic_whenInitialized_thenShowLoading() = runTest { fun uiStateTopic_whenInitialized_thenShowLoading() = runTest {
viewModel.uiState.test { assertEquals(TopicUiState.Loading, viewModel.uiState.value.topicState)
assertEquals(TopicUiState.Loading, awaitItem().topicState)
}
} }
@Test @Test
fun uiStateTopic_whenFollowedIdsSuccessAndTopicLoading_thenShowLoading() = runTest { fun uiStateTopic_whenFollowedIdsSuccessAndTopicLoading_thenShowLoading() = runTest {
viewModel.uiState.test { val collectJob = launch(UnconfinedTestDispatcher()) { viewModel.uiState.collect() }
userDataRepository.setFollowedTopicIds(setOf(testInputTopics[1].topic.id)) userDataRepository.setFollowedTopicIds(setOf(testInputTopics[1].topic.id))
assertEquals(TopicUiState.Loading, awaitItem().topicState) assertEquals(TopicUiState.Loading, viewModel.uiState.value.topicState)
}
collectJob.cancel()
} }
@Test @Test
fun uiStateTopic_whenFollowedIdsSuccessAndTopicSuccess_thenTopicSuccessAndNewsLoading() = fun uiStateTopic_whenFollowedIdsSuccessAndTopicSuccess_thenTopicSuccessAndNewsLoading() =
runTest { runTest {
viewModel.uiState.test { val collectJob = launch(UnconfinedTestDispatcher()) { viewModel.uiState.collect() }
awaitItem()
topicsRepository.sendTopics(testInputTopics.map { it.topic }) topicsRepository.sendTopics(testInputTopics.map { it.topic })
userDataRepository.setFollowedTopicIds(setOf(testInputTopics[1].topic.id)) userDataRepository.setFollowedTopicIds(setOf(testInputTopics[1].topic.id))
val item = awaitItem() val item = viewModel.uiState.value
assertTrue(item.topicState is TopicUiState.Success) assertTrue(item.topicState is TopicUiState.Success)
assertTrue(item.newsState is NewsUiState.Loading) assertTrue(item.newsState is NewsUiState.Loading)
}
collectJob.cancel()
} }
@Test @Test
fun uiStateTopic_whenFollowedIdsSuccessAndTopicSuccessAndNewsIsSuccess_thenAllSuccess() = fun uiStateTopic_whenFollowedIdsSuccessAndTopicSuccessAndNewsIsSuccess_thenAllSuccess() =
runTest { runTest {
viewModel.uiState.test { val collectJob = launch(UnconfinedTestDispatcher()) { viewModel.uiState.collect() }
awaitItem()
topicsRepository.sendTopics(testInputTopics.map { it.topic }) topicsRepository.sendTopics(testInputTopics.map { it.topic })
userDataRepository.setFollowedTopicIds(setOf(testInputTopics[1].topic.id)) userDataRepository.setFollowedTopicIds(setOf(testInputTopics[1].topic.id))
newsRepository.sendNewsResources(sampleNewsResources) newsRepository.sendNewsResources(sampleNewsResources)
val item = awaitItem() val item = viewModel.uiState.value
assertTrue(item.topicState is TopicUiState.Success) assertTrue(item.topicState is TopicUiState.Success)
assertTrue(item.newsState is NewsUiState.Success) assertTrue(item.newsState is NewsUiState.Success)
}
collectJob.cancel()
} }
@Test @Test
fun uiStateTopic_whenFollowingTopic_thenShowUpdatedTopic() = runTest { fun uiStateTopic_whenFollowingTopic_thenShowUpdatedTopic() = runTest {
viewModel.uiState val collectJob = launch(UnconfinedTestDispatcher()) { viewModel.uiState.collect() }
.test {
awaitItem()
topicsRepository.sendTopics(testInputTopics.map { it.topic }) topicsRepository.sendTopics(testInputTopics.map { it.topic })
// Set which topic IDs are followed, not including 0. // Set which topic IDs are followed, not including 0.
userDataRepository.setFollowedTopicIds(setOf(testInputTopics[1].topic.id)) userDataRepository.setFollowedTopicIds(setOf(testInputTopics[1].topic.id))
@ -137,9 +143,10 @@ class TopicViewModelTest {
assertEquals( assertEquals(
TopicUiState.Success(followableTopic = testOutputTopics[0]), TopicUiState.Success(followableTopic = testOutputTopics[0]),
awaitItem().topicState viewModel.uiState.value.topicState
) )
}
collectJob.cancel()
} }
} }

Loading…
Cancel
Save