'coroutine nested exception problem on unit test
Can somebody explain why the exception problem is happening only in unit test? I was testing exceptional case for flow and I found exception does not throw as I expected.
val dispatcher = TestCoroutineDispatcher()
try {
dispatcher.runBlockingTest {
flow<Resource<Int>> {
println("1. body thread: ${Thread.currentThread().name}")
throw FlowFailureException()
}
.catch { e ->
emit(Resource.Error(RootFlowFailureException(cause = e)))
}
.flowOn(Dispatchers.Default)
.map {
println("2. map thread: ${Thread.currentThread().name}")
when (it) {
is Resource.Success<Int> -> it.data
is Resource.Error -> {
throw IllegalStateException(it.exception)
}
}
}
.collect()
}
} catch (e: Throwable) {
println("catching exception: ${e.javaClass}")
e.printAll()
assertThat(e.javaClass, equalTo(IllegalStateException::class.java))
// problem happened here
assertThat(e.cause?.javaClass, equalTo(RootFlowFailureException::class.java))
assertThat(e.cause?.cause?.javaClass, equalTo(FlowFailureException::class.java))
assertThat(e.cause?.cause?.cause, `is`(nullValue()))
}
sealed class Resource<out R> {
data class Success<out T>(val data: T) : Resource<T>()
data class Error(val exception: Throwable) : Resource<Nothing>()
override fun toString(): String {
return when (this) {
is Success<*> -> "Success[data=$data]"
is Error -> "Error[exception=$exception]"
}
}
}
class RootFlowFailureException(
message: String? = null,
cause: Throwable? = null
) : RuntimeException(message, cause)
class FlowFailureException(
message: String? = null,
cause: Throwable? = null
) : RuntimeException(message, cause)
# system logs
System.out: 1. body thread: DefaultDispatcher-worker-1 @coroutine#2
System.out: 2. map thread: Test worker @coroutine#1
System.out: catching exception: class java.lang.IllegalStateException
System.out: e> class java.lang.IllegalStateException
System.out: e> class java.lang.IllegalStateException
System.out: e> class org.test.FlowOperatorTest$RootFlowFailureException
System.out: e> class org.test.FlowOperatorTest$FlowFailureException
I expected exception hierarchy as follows:
IllegalStateException -> RootFlowFailureException -> FlowFailureException
But actual exception hierarchy was:
IllegalStateException -> IllegalStateException -> RootFlowFailureException -> FlowFailureException
This case doesn't happen in ViewModel (real implementation) and it only happened in unit test. So I assume that it is because of TestCoroutineDispatcher or TestCoroutineExceptionHandler that handles exception or coroutine.
Does anyone have idea to this issue?
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
