You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Mockito拦截错误协程致Kotlin协程同步逻辑失效问题排查

问题分析与解决方案

问题根源

你的问题核心在于挂起函数的执行时机+Mockito拦截时的协程上下文处理不当:

  1. first()是挂起函数,但内部使用了async且未等待其完成(即没有调用await()),导致first()会提前返回,而内部协程在后台继续执行。
  2. 你原拦截代码中,it.callRealMethod()直接调用挂起函数,但未在协程上下文里等待其真正完成,also块里的自定义代码是在first()返回后才执行,此时second()已经开始运行,所以出现了first→second→in between的错误顺序。

修正方案

根据first()的内部逻辑,分两种情况处理:

情况1:first()本身是正确的挂起函数(内部已await所有异步任务)

直接将callRealMethod()和自定义代码放在同一个runBlocking中,确保first()完全执行完毕后再执行自定义代码:

doAnswer {
    runBlocking {
        // 等待挂起函数first()完全执行结束
        it.callRealMethod()
        // 执行你需要插入的自定义代码
        lock1.unlock()
        lock.lock()
    }
}.whenever(b).first()

情况2:first()内部用了async但未await(返回Deferred)

如果first()的代码类似这种:

suspend fun first(): Deferred<Unit> {
    return async {
        println("first")
    }
}

那需要在拦截时主动await返回的Deferred,确保内部异步任务完成:

doAnswer {
    runBlocking {
        val deferredTask = it.callRealMethod() as Deferred<*>
        // 等待内部async任务执行完毕
        deferredTask.await()
        // 执行自定义代码
        lock1.unlock()
        lock.lock()
    }
}.whenever(b).first()

为什么原方案可行

你之前拦截second()时,相当于在second()执行前加了锁等待,自然能保证顺序;而移除first()里的async后,first()变成普通挂起函数,会同步执行完毕再返回,所以拦截逻辑也能正常工作。

内容的提问来源于stack exchange,提问作者Gabriel Furstenheim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 00:06:04