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