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