How to test `MutableSharedFlow` with `replay=0`? I...
# coroutines
k
How to test
MutableSharedFlow
with
replay=0
? I'm using turbine for testing Kotlin Flows and I managed to write tests for
MutableStateFlow
, but the same emitted values doesn't work for SharedFlows.
e
Without replay, the shared flow won't emit to late collectors!
So first call
sharedFlow.test {
Then interleave assertions and emissions of values before
}
k
You mean emit values inside
test { }
block only?
e
Well, that depends on what you want to test
If you want to test that emissions are dropped without subscribers, then emit outside of the test block
k
I believe with the introduction of
SharedFlow
and
StateFlow
, Channels are considered to be low level APIs. So, I'm trying to use
MutableSharedFlow
to build a mock class wrapping some state and I use public methods of this clas to mutate that state, thus, transformed objects are emitted to a private
MutabelSharedFlow
and a Public Flow is where I'm expecting those changes to appear. So I was calling that public method in
@Before
section and was expecting those events to appear in
SharedFlow
unit test. Will try your suggested approach and let you know how it goes. Thanks!
e
Channels are fine to be used! They still have use cases. There are specific channel implementations that are now obsolete since shared and state flows exist
u
yes .test first
k
@Erik can you point to some talk/article explaining use cases of SharedFlow/StateFlow vs the Channels and Actors
e
A few examples: https://elizarov.medium.com/shared-flows-broadcast-channels-899b675e805c If course, not all use cases can be described in one place, but in general these examples apply to many cases
k
It works this way. Am I doing it right?
e
No need to
launch
You can
Copy code
flow.test {
    // assert initial behaviour, e.g. emission(s) or error

    // call stuff that should make the flow do something
    // assert that the flow does it

    // repeat previous steps as often as you like

    // assert final state, e.g. flow completed or flow does nothing more
}
k
Could be done, thought doing it this way might mimic operating in different coroutines as everything inside
test { }
is run within same Job and we should mainly be doing collect operations there.
e
The benefit is that you assert the actions and flow's events in the order that they happen
If you do all actions and just assert the correct events afterwards, you aren't sure about what events happened on what actions. That might be good enough, but in some cases actual behaviour testing can be preferable
👍 1
In the latter case you don't need Turbine, though. You could just collect the flow as a list (if it completes, shared flows never complete. If a shared flow, you could e.g.
take
values), and assert that the list is as expected.
k
Yes I agree. I was just trying to create simplistic example to ask the question and I do got the clarification about
SharedFlow
I needed. Will be useful in some complex scenarios I have in the codebase.