Hello everyone! I'm trying to migrate to 1.6.10 co...
# coroutines
r
Hello everyone! I'm trying to migrate to 1.6.10 coroutines-test and have a ViewModel that contains a flow using the
mapLatest
operator. More details in the thread with code examples.
👀 1
Created this public repo to show an example of this test failing: https://github.com/roudikk/map-latest-test If you check the ViewModel, the
onValue
function is emitting a new value to a shared flow, which then uses
mapLatest
and updates the stateFlow with the new state. I created a function called
runCancellingTest
which cancels the flows that are launched within a test scope to prevent the exception of still having active jobs. That function takes an optional context with a
StandardTestDispatcher
being the default. When I run the test with that dispatcher, emitting a new value to the shared flow does not trigger the
mapLatest
operator and result in a time out when awaiting the second emission. Switching
mapLatest
to
map
will make the test succeed but will result in unwanted behaviour since in our real scenario we have delay in
mapLatest
and want it to cancel the last operation. Also using
UnconfinedTestDipsatcher
instead will make the test work too but shouldn't we be using
StandardTestDispatcher
? Thank you.
One more thing, also putting a
replay = 1
on the
MutableSharedFlow
also will pass the test but does result in unwanted behaviour
n
StandardTestDispatcher
doesn't run dispatched work on it's own. You have to tell it to run the pending work:
Copy code
viewModel.stateFlow.test {
    runCurrent()
    assert(awaitItem() == "Me!")
    viewModel.onValue("There")
    runCurrent()
    assert(awaitItem() == "Hello: There")
}
FYI, your TestViewModel does not maintain the ordering of
onValue
calls. If you call
onValue("hi");onValue("bye")
then
testStringFlow
could emit "bye" and then "hi" depending on the dispatcher.
launch
starts concurrent work, The code inside two different
launch
lambdas can run in any order. This is partly due to multi-threading, but also
Dispatchers.Default
and
<http://Dispatchers.IO|Dispatchers.IO>
don't even distribute the work to threads in a FIFO manner. This can even be true for single threaded dispatchers like inside
runBlocking
or
Main.immediate
.
r
Ahh thanks @Nick Allen that makes sense, originally I had the
runCurrent
before the
onValue
call so i was missing the one in the beginning. As for the ordering, I completely agree! It's just a poor simple example where I wanted to show it not collecting in test. Also explains why using
replay = 1
would make it pass since the
test
function is collecting the replayed value to that subscriber.