azabost
05/13/2022, 12:12 PMSharedFlow
collection?
Let’s say:
class MyClass(coroutineScope: CoroutineScope, flowToCollect: Flow<Int>) {
var lastObservedResult: Int? = null
init {
coroutineScope.launch {
flowToCollect.collect { lastObservedResult = it }
}
}
}
If I use runTest
and pass the created TestScope
then the test is going to fail after some time because there is a running coroutine.
@Test
fun testMyClass() = runTest {
MyClass(this, flow)
// do something here, make some assertions etc.
// at the end, the test is going to fail because of the running coroutine
}
After waiting for 60000 ms, the test coroutine is not completing, there were active child jobs (...)
So should I create another scope instead? Like this, for example?
val dispatcher = UnconfinedTestDispatcher()
@Test
fun testMyClass() = runTest(dispatcher) {
val additionalScope = CoroutineScope(dispatcher)
MyClass(additionalScope, flow)
// do something here, make some assertions etc.
additionalScope.close() // Is this necessary, btw? Is the launched coroutine going to leak after the test is finished or something?
// now the test won't fail, but I must remember to close the additional scope manually
}
Dmitry Khalanskiy [JB]
05/13/2022, 12:57 PMazabost
05/13/2022, 12:58 PMDmitry Khalanskiy [JB]
05/13/2022, 1:04 PMazabost
05/13/2022, 1:18 PMMichal Klimczak
06/12/2022, 10:42 AMrunTest
scope to run the neverending coroutine, and then try to cancel the scope, the test fails with
kotlinx.coroutines.JobCancellationException: TestScopeImpl was cancelled; job=TestScope[test ended]
E.g.
runTest(UnconfinedTestDispatcher()) {
val counter = Counter(this)
...
this.cancel()
}
What works fine instead is this.coroutineContext.cancelChildren()
. Is this the right thing to do?
Also, my class has a dispose
function which calls the passedScope.cancel()
. I could use the dispose()
function to be more explicit about what should be done, but the exception prevents that