azabost
03/11/2020, 10:58 AMFlow.launchIn()
says it is “a shorthand for `scope.launch { flow.collect() }`” but when I compare behaviors in unit tests it is a little different.
Having a simple flow:
private val integersFlow = flow {
var i = 1
while(true) {
delay(100)
emit(i++)
}
}
and using test scope and dispatcher:
private val observingScopeJob1 = SupervisorJob()
private val observingScope1 = CoroutineScope(observingScopeJob1)
private val testDispatcher = TestCoroutineDispatcher()
When I do the following:
@Test
fun `should receive 10 integers - collect`() = runBlocking {
var observedIntegers = 0
observingScope1.launch(testDispatcher) {
integersFlow.collect {
observedIntegers++
}
}
observedIntegers.shouldEqual(0)
testDispatcher.advanceTimeBy(1000)
observedIntegers.shouldEqual(10)
Unit
}
the test passes ✅
but when I convert it into RxJava-style like this:
@Test
fun `should receive 10 integers - launchIn`() = runBlocking {
var observedIntegers = 0
integersFlow
.onEach { observedIntegers++ }
.flowOn(testDispatcher)
.launchIn(observingScope1)
observedIntegers.shouldEqual(0)
testDispatcher.advanceTimeBy(1000)
observedIntegers.shouldEqual(10)
Unit
}
the test fails ❎
unless I add an additional delay(100)
before testDispatcher.advanceTimeBy(1000)
which seems very weird to me. Like… why is that needed to delay the main thread in unit test to allow the collecting coroutine to be launched at all?louiscad
03/11/2020, 11:39 AMflowOn
while the other changes the dispatcher of the scope.
Two solutions to have equivalence between the two:
1. Don't pass testDispatcher
to launch
and use flowOn
instead, like in the second snippet.
2. Remove flowOn
and put the testDispatcher
in the scope (e.g. using launchIn(observingScope1 + testDispatcher)
).azabost
03/11/2020, 12:25 PM