kotlinx.coroutines
kotlinx.coroutines copied to clipboard
[Test - coroutine 1.6.0] Unexpectedly propagate the exception thrown in an async {} block out to runTest return
In normal coroutine cases, all things occured in async{} block should be confined in the returned Deferred object, and let the caller to determine the futher usage, such as calling await(), or getCompletionExceptionOrNull(), ... etc.
When using runTest{}, if we throw an exception in an async{} block, this exception is catched in the returned Deferred object, and this program continues running. But after runTest returns, this exception is unexpectedly thrown outside runTest{} block, and will cause testing failure
@Test
fun test() = runTest {
val deferred = async {
throw Exception()
}
println("This line is still running")
// Maybe doing something for deferred
}
As the following output:
This line is still running
java.lang.Exception
at xxx.xxx.xxx.xxx.invokeSuspend(xxxxx:xx)
...
Library versions:
kotlin-stdlib:1.6.10 kotlinx-coroutines-jdk8:1.6.0 kotlinx-coroutines-test:1.6.0
Failures in child coroutines are typically propagated to parents. In this case, async creates a coroutine that is a child to main one created for the test. Working as intended. Do you have examples of this working differently?
I would like to add my +1 here
I think that as long as the behavior is consistent, then that's a design choice of the language.
But the fact that CustomException behaves differently from IllegalStateException I think is a bug - I would except these 2 programs to behave in the exact same way.
(These are not my examples, the author is welcome to chime in & take credit)
The examples you provided differ in ways other than the exceptions used. If you take one example and just replace throw CustomException() with check(1 == 2) or vice versa, the behavior stays the same. So, the exceptions don't behave differently, and there's no reason why they should.
Apologies, I did not include the right comparative examples; I've updated my original post but am also reposting the correction here.
I expect that these 2 programs, one throwing CustomException & the other IllegalStateException, would behave the same & consistently
Ah nevermind it's because JobCancellationException is a IllegalStateException 🤦♂️
Alright I retract my +1, although maybe it makes sense to have CancellationException not be a IllegalStateException? 🤷♂️ But I guess this matches java.util.concurrent, so... c'est la vie.
One just has to be careful with catching IllegalStateException with coroutines I suppose