I have a question around testing.. If I have a Mut...
# coroutines
t
I have a question around testing.. If I have a MutableStateFlow, and a function which updates that StateFlow multiple times, is there a way to test that the StateFlow went through the expected intermediate states?
Copy code
val myStateFlow = MutableStateFlow<Int>(1)

fun updateStateFlow() {
    myStateFlow.value = 2
    myStateFlow.value = 3
}

@Test
fun testStateFlow() {
    assertEquals(1, myStateFlow.value)

    updateStateFlow()

    assertEquals(2, myStateFlow.value) // Obviously this will fail
    assertEquals(3, myStateFlow.value)
}
j
t
I have used this before. But I’m curious whether this can be done without Turbine
I mean - I’m sure it can.. I thought there was some incantation around collecting the flow like so:
Copy code
val collectJob = launch(UnconfinedTestDispatcher()) { myStateFlow.collect() }
But I don’t recall or understand this!
j
You need two things: • The
Unconfined
dispatcher. This will ensure that your collector coroutine can be started in the same stackframe as the one updating the value. • A non-suspending collector. This ensures that there's no possibility for the upstream to conflate updates. This is what Turbine does. It also uses
UNDISPATCHED
to launch its coroutine to ensure collection starts synchronously rather than upon first suspension.
so something like
Copy code
val values = mutableListOf<Int>()
launch(UNDISPATCHED, Unconfined) {
  myStateFlow.collect { values += it }
}

assertEquals(listOf(1), values)

updateStateFlow()
assertEquals(listOf(1, 2, 3), values)
t
OK, thanks Jake. I think I have the rough gist of how this works. I can see why I’d probably just use Turbine 😅
j
Yeah there's not much to Turbine. The only difference is that we use an unlimited Channel because the collector coroutine could be resumed on multiple threads and we need a synchronization primitive to ensure everything gets added correctly. Then you basically just call
receive()
to read values. And that is also the mechanism that will suspend waiting for new values to arrive.