Osip Fatkullin
08/09/2023, 5:05 PMDispatchers.Main from coroutines under the hood?
Environment: I use Kotest 5.6.2 and have enabled coroutineTestScope and timeout = 5.seconds
When I call Dispatchers.setMain right before test, everything is OK:
class MySpec : FeatureSpec({
val dispatcher = StandardTestDispatcher()
feature("...") {
Dispatchers.setMain(dispatcher)
scenario("...") {
// It will crash if Main dispatcher was not set before
launch(Dispatchers.Main) {
delay(100)
}.join()
dispatcher.scheduler shouldBe testCoroutineScheduler // PASSED!
}
Dispatchers.resetMain()
}
})
But when I set Main dispatcher in beforeTest or beforeSpec, I get `TimeoutCancellationException`:
class MySpec : FeatureSpec({
val dispatcher = StandardTestDispatcher()
beforeTest { Dispatchers.setMain(dispatcher) }
afterTest { Dispatchers.resetMain() }
feature("...") {
scenario("...") {
// It will crash if Main dispatcher was not set before
launch(Dispatchers.Main) {
delay(100)
}.join()
dispatcher.scheduler shouldBe testCoroutineScheduler // PASSED!
}
} // CRASH after the test
})
---
Timed out waiting for 5000 ms
kotlinx.coroutines.TimeoutCancellationException: Timed out waiting for 5000 ms
at app//kotlinx.coroutines.TimeoutKt.TimeoutCancellationException(Timeout.kt:184)
...
at io.kotest.engine.test.TestInvocationInterceptor.intercept(TestInvocationInterceptor.kt:31)
at io.kotest.engine.test.TestCaseExecutor$execute$3$1.invokeSuspend(TestCaseExecutor.kt:97)
...
What am I doing wrong?Lukasz Kalnik
08/23/2023, 7:18 AMcoroutineContext inside the lifecycle hooks (or tests):
beforeTest { Dispatchers.setMain(coroutineContext[CoroutineDispatcher]!!) }Lukasz Kalnik
08/23/2023, 7:20 AMcoroutineTestScope = true at the beginning of the spec):
class MySpec : FeatureSpec({
coroutineTestScope = true
val dispatcher = StandardTestDispatcher()
beforeTest { Dispatchers.setMain(dispatcher) }
afterTest { Dispatchers.resetMain() }
feature("...") {
scenario("...") {
// It will crash if Main dispatcher was not set before
launch(Dispatchers.Main) {
delay(100)
}.join()
}
}
})Osip Fatkullin
09/18/2023, 9:09 AMclass KotestConfig : AbstractProjectConfig() {
override val coroutineTestScope = true
override val timeout = 5.seconds
}
But I have no idea whyLukasz Kalnik
09/18/2023, 9:10 AMOsip Fatkullin
09/18/2023, 9:17 AMTimeoutCancellationException happen.Osip Fatkullin
09/18/2023, 9:35 AMinvocationTimeout instead of timeout, it works without TimeoutCancellationException . The difference I found between these options is that timeout applies to test containers, but invocationTimeout is not.Osip Fatkullin
09/18/2023, 10:30 AMTimed out after 5s of _virtual_ (kotlinx.coroutines.test) time. To use the real time, wrap 'withTimeout' in 'withContext(Dispatchers.Default.limitedParallelism(1))'
kotlinx.coroutines.TimeoutCancellationException: Timed out after 5s of _virtual_ (kotlinx.coroutines.test) time. To use the real time, wrap 'withTimeout' in 'withContext(Dispatchers.Default.limitedParallelism(1))'
I’ve filed issue on GitHub: https://github.com/kotest/kotest/issues/3703