Mockito拦截错误协程致Kotlin协程同步逻辑失效问题排查
问题分析与解决方案
问题根源
你的问题核心在于挂起函数的执行时机+Mockito拦截时的协程上下文处理不当:
first()是挂起函数,但内部使用了async且未等待其完成(即没有调用await()),导致first()会提前返回,而内部协程在后台继续执行。- 你原拦截代码中,
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
相关产品推荐
相关产品推荐

