suspendCoroutine 在调用 mockk mock 的情况下,当调用 resumeWithException 时会挂起。

huangapple go评论56阅读模式
英文:

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
}

huangapple
  • 本文由 发表于 2023年5月29日 18:25:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/76356532.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定