Benoît
01/17/2022, 11:37 AMclass MyContainerHost(
scope: CoroutineScope,
val repositoryFlow: Flow<String?>, // Flow representing repository state
val requestRefresh: () -> Unit
) :
ContainerHost<String, String> {
override val container: Container<String, String> =
scope.container("initial") {
// When creating the container, listen for update on the Repository flow
scope.launch {
repositoryFlow.collect { newState ->
intent {
// When no state in flow, refresh it
if (newState != null) {
reduce { newState }
} else {
requestRefresh()
}
}
}
}
}
}
The thing is when I write a unit test for that, the test returns before being able to get into my collect{}
block.
How would you deal with that?
ThanksBenoît
01/17/2022, 11:37 AMval repositoryFlow = MutableStateFlow<String?>(null)
val containerHost = MyContainerHost(
this,
repositoryFlow = repositoryFlow,
requestRefresh = {
// This does not get called
repositoryFlow.tryEmit("refreshed state")
}
).test("initial")
containerHost.runOnCreate()
containerHost.assert("initial") {
states(
// This gives "expected states but never received"
{ "refreshed state" }
)
}
Mikolaj Leszczynski
01/17/2022, 12:33 PMintent
instead. No need for launching an extra new coroutine, as that’s what intent
does anyway.Mikolaj Leszczynski
01/17/2022, 12:34 PMMikolaj Leszczynski
01/17/2022, 12:35 PMclass MyContainerHost(
scope: CoroutineScope,
val repositoryFlow: Flow<String?>, // Flow representing repository state
val requestRefresh: () -> Unit
) :
ContainerHost<String, String> {
override val container: Container<String, String> =
scope.container("initial") {
// When creating the container, listen for update on the Repository flow
intent {
repositoryFlow.collect { newState ->
// When no state in flow, refresh it
if (newState != null) {
reduce { newState }
} else {
requestRefresh()
}
}
}
}
}
}
Benoît
01/17/2022, 1:03 PMMikolaj Leszczynski
01/17/2022, 1:42 PMContainerHost
using `Flow`s need special treatment.
There are a few options here I think.
1. Provide a finite flow as repositoryFlow
2. You can runOnCreate
in your test in a launched coroutine so it doesn’t block your test
3. You can use liveTest
Mikolaj Leszczynski
01/17/2022, 1:42 PMMikolaj Leszczynski
01/17/2022, 1:43 PMintent
will finish and the test can carry on.Mikolaj Leszczynski
01/17/2022, 1:44 PMBenoît
01/17/2022, 2:11 PMMutableStateFlow
so I can send a bunch of stuff at different moment in time
2. This caused "expected states but never received", which makes sense, the runOnCreate
doesn't get enough time to run before the assertion
3. What do you mean liveTest? How do I do that?Mikolaj Leszczynski
01/17/2022, 2:19 PMContainerHost.liveTest
for this.
The assertions still work - they await for emissions from state and side effect flows with a timeout. So you can treat the rest of the test the same I think.Mikolaj Leszczynski
01/17/2022, 2:19 PMliveTest
will work best @BenoîtMikolaj Leszczynski
01/17/2022, 2:19 PMBenoît
01/17/2022, 2:26 PMliveTest
is what I needed this whole time, thanks a lot @Mikolaj Leszczynski!
Btw there's no mention of liveTest
on https://orbit-mvi.org/Test/overview/, might be a good idea to add itMikolaj Leszczynski
01/17/2022, 2:34 PMRak
01/18/2022, 11:44 AMrunTest
?Benoît
01/18/2022, 11:50 AMrunTest
isn't strictly equal to runBlocking
, if a test passes with runBlocking
you can't (always) simply change it to runTest
and expect it to pass as well. Sometimes the order of execution can differ