Corey
10/19/2023, 12:57 PMstateIn
operator? Given the fake code below when running tests using Turbine they will never emit anything. They do emit if I remove stateIn
and move everything to a function.
Service = suspend fun fetchData(): String = "Hello World"
FlowService = fun fetchData(): Flow<String> = flow {
emit("hi there") /* some cold emission */
}
class ViewModel(
coroutineScope: CoroutineScope,
service: Service,
flowService: FlowService
) {
val state1: StateFlow<String> = flow { emit(service.fetchData()) }.stateIn(coroutineScope, SharingStarted.WhileSubscribed(5000), "Loading")
val state2: StateFlow<String> = flowService.fetchData().stateIn(coroutineScope, SharingStarted.WhileSubscribed(5000), "Loading")
}
@Test fun expectStates() = scope.runTest {
turbineScope {
val viewModel = ViewModel(scope, Service(), FlowService())
// fails
viewModel.state1.test {
assertEquals("Loading", awaitItem())
assertEquals("Hello World", awaitItem())
cancelAndIgnoreRemainingEvents()
}
// fails
viewModel.state2.test {
assertEquals("Loading", awaitItem())
assertEquals("Hello World", awaitItem())
cancelAndIgnoreRemainingEvents()
}
// fails
backgroundScope.launch(UnconfinedTestDispatcher(testScheduler)) {
viewModel.state2.collect()
}
viewModel.state2.test {
assertEquals("Loading", awaitItem())
assertEquals("Hello World", awaitItem())
cancelAndIgnoreRemainingEvents()
}
}
}
jw
10/19/2023, 1:03 PMturbineScope
here because you're not using any standalone `Turbine`stest { }
block to fail because it will never see Loading
test
blocks to fail because no time has elapsed to restart the upstream collection and re-trigger emission of Loading
cancelAndIgnoreRemainingEvents()
callsTurbine
at all when testing a StateFlow
. You can do normal assertions against its .value
Corey
10/19/2023, 1:11 PMjw
10/19/2023, 1:15 PMbackgroundScope
it will be automatically canceled when the test ends.Corey
10/19/2023, 1:26 PM