Closed
Description
On Android, the viewmodels rely on viewModelScope
, which is essentially the same as CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
. If I update a MutableStateFlow
multiple times inside viewModelScope.launch
I don't seem to be able to collect/intercept anything except the last value set. I already tried changing dispatchers and/or adding runCurrent
but it won't collect anything else other than the last value emitted in that scope.
P.S. This used to not be a problem with TestCoroutineDispatcher
+ TestCoroutineScope
.
class SomeViewModelTest {
@Before
fun setup() {
Dispatchers.setMain(UnconfinedTestDispatcher())
}
@Before
fun teardown() {
Dispatchers.resetMain()
}
@Test
fun testAllEmissions() = runTest {
val values = mutableListOf<Int>()
val stateFlow = MutableStateFlow(0)
val job = launch(UnconfinedTestDispatcher(testScheduler)) { // <------
stateFlow.collect {
values.add(it)
}
}
val viewModelScope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
viewModelScope.launch {
runCurrent()
stateFlow.value = 1
runCurrent()
stateFlow.value = 2
runCurrent()
stateFlow.value = 3
runCurrent()
}
viewModelScope.cancel()
job.cancel()
// each assignment will immediately resume the collecting child coroutine,
// so no values will be skipped.
assertEquals(listOf(0, 1, 2, 3), values) // FAILURE
}
}
Above test fails with is expected:<[0, 1, 2, 3]> but was:<[0, 3]>