英文:
suspendCoroutine hangs when resumeWithException is called with mockk mock
问题
以下是您要翻译的内容:
"如果我按原样执行这个测试,异常会被抛出,测试会变成红色,正如预期的那样。但是,如果我注释掉使用IllegalStateException
构造函数的调用,而改用mockk
模拟,测试会无限期地挂起,我永远不会从suspendCoroutine
块中返回。我该怎么办?"
英文:
I have an external API that I want to test against, but in which I cannot construct exceptional types myself. Consider this following small example:
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import org.junit.jupiter.api.Test
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine
class Foo {
lateinit var cb: Callback
interface Callback {
fun good()
fun bad(e: Throwable)
}
fun something(cb: Callback) {
this.cb = cb
}
}
class Test {
@OptIn(DelicateCoroutinesApi::class)
@Test
fun test() {
val foo = Foo()
runBlocking {
launch {
delay(300)
//foo.cb.bad(mockk<IllegalStateException>(relaxed = true))
foo.cb.bad(IllegalStateException())
}
GlobalScope.async {
suspendCoroutine { cont ->
foo.something(object : Foo.Callback {
override fun good() {
cont.resume(Unit)
}
override fun bad(e: Throwable) {
cont.resumeWithException(e)
}
})
}
}.await()
}
}
}
If I execute this test as-is, the exception is thrown and the test turns red, just as expected. If I however comment out the call with the IllegalStateException
constructor and use the mockk mock instead, the test hangs indefinitely and I never return from the suspendCoroutine
block. What can I do?
答案1
得分: 1
该行为源自您使用了一个Exception
的放松模拟,该模拟在调用getCause
时返回一个放松模拟。当resumeWithException
内部的某个机制尝试获取异常的根本原因时,这导致无限递归。
您可以通过简单地指定模拟异常的原因来修复此问题,例如:
every { cause } returns null
}
英文:
The behavior arises from the fact that you use a relaxed mock of an Exception
that returns a relaxed mock when getCause
is called. This leads to an infinite recursion when some mechanism inside of resumeWithException
tries to get the root cause of your exception.
You can fix this by simply specifying the cause of your mocked exception, e.g.
mockk<IllegalStateException>(relaxed = true) {
every { cause } returns null
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论