I updated Kotlin coroutines to v1.6.0 and while addressing the changes in the tests I stumbled upon an issue when trying to test intermediate emissions. There's a section in the migration guide describing how to go about writing this kind of test, but the proposed solution is not fully working and I'd like to understand where's my mistake.
In particular, I have a StateFlow
that gets updated twice in a coroutine launched in the viewModelScope
(which internally uses Dispatchers.Main.immediate
). However, when testing, the intermediate emission is not collected.
Simplified example:
class VM : ViewModel() {
val stateFlow = MutableStateFlow("a")
fun foo() {
viewModelScope.launch {
stateFlow.value = "b"
// [...] call to a suspend fun
stateFlow.value = "c"
}
}
}
class AbcTest {
@Test
fun testFlow() {
Dispatchers.setMain(UnconfinedTestDispatcher())
runTest {
val vm = VM()
val values = mutableListOf<String>()
val job = launch(UnconfinedTestDispatcher(testScheduler)) {
vm.stateFlow.collect(values::add)
}
vm.foo()
job.cancel()
assertEquals(listOf("a", "b", "c"), values)
}
Dispatchers.resetMain()
}
}
This test fails with: expected: <[a, b, c]> but was: <[a, c]>
.
What am I missing?