How can you easily assert values emitted by a flow...
# coroutines
e
How can you easily assert values emitted by a flow that doesn't complete? Using
TestCoroutineScope
/
-Dispatcher
with
runBlockingTest
, when you
flow.launchIn(testScope)
, then the job would leak unless you remember to cancel the job before the test block ends. How can you verify more easily that a flow emitted certain values? I can think of some solutions: 1. As a side effect, put collected values in some mutable collection. This makes assertion of values easy, but you still have to remember to cancel any collectors of the uncompleted flow. 2. Cancel the source of the flow, i.e. force it to complete, by the end of the test. This should usually also complete collectors. 3. Do not use the test coroutine scope to collect flows that do not complete. This has a downside that you test with multiple scopes, which may be conceptually challenging. Either way it's a bit of test boilerplate 👎 Any ideas?
👍 1
i
💯 2
f
a
turbine has a pretty excellent api for this
e
Not yet, will do! Thanks Ian. I'm trying to get rid of a different dependency, which introduces my need to test flow values, so I'm not eager to introduce Yet Another Thing. However, a dep just for testing is a step forward.
Also, the gist of it is that if you can't get values out of a flow, then you need to assert them inside of a collector. That concept is helpful
d
The only disadvantage of Turbine seems to be that you can't keep a Given/When/Then structure when testing events, since the
test { }
needs to be run before the When and IS the Then already... 🤕
e
That's right. You can do a composed version of given when then, though. But that's harder to read, which is not nice in tests
d
It looks like https://github.com/floschu/coroutines-test-extensions mentioned is better in that regard... it seems to just collect all emissions in a List and allow testing on it... it even `launch`es each TestFlow with
testIn
whereas with Turbine, you need to launch yourself... Did you end up using Turbine, Erik?
e
I did. It works well for my use cases, but I did notice this limitation too
d
I guess I figured it out... the difference between the two is that Turbine allows testing WHEN the emissions are supposed to be emitted (see https://github.com/cashapp/turbine/issues/19) and the When's are meant to be put wherever between emissions that might be required to test the timing. Whereas the second lib is when timing is not important and all you need is to test what was emitted.
f
Using a
TestCoroutineScope
to launch the
TestFlow
in, also allows to test timing due to the
DelayController
d
Timing like advanceBy, but to call a side-effect while TestFlow is collecting, it won't stop collecting to let you test the current contents... it'll keep on collecting, and when you use the expectation api it'll test on the state it's holding then...