Kotlin MockK如何验证后台协程作用域中的方法调用?
问题原因与解决方案
核心问题
测试失败的根本原因是ViewModel的backgroundScope未使用测试指定的testDispatcher,导致runCurrent()无法触发该协程执行,最终interactor.doBackground(null)从未被调用。
真机上backgroundScope依赖默认Dispatcher(如Dispatchers.IO)能正常执行,但测试中你没有将这个Dispatcher替换为测试可控的Dispatcher,协程会挂起在测试框架无法调度的线程上,自然不会被执行。
修复步骤
1. 让ViewModel支持Dispatcher注入(推荐)
修改ViewModel构造函数,将Dispatcher作为依赖传入,方便测试时替换:
class MyViewModel( private val interactor: MyInteractor, private val backgroundDispatcher: CoroutineDispatcher = Dispatchers.IO ) : ViewModel() { private val backgroundScope = CoroutineScope(backgroundDispatcher + genericErrorHandler) fun makeBackgroundCallAndClose() { backgroundScope.launch(genericErrorHandler) { interactor.doBackground(null) } navigate(NavigatorCommand.CloseScreen) } }
2. 调整测试代码,绑定测试Dispatcher
- 创建
TestScope时关联testDispatcher - 给ViewModel传入测试Dispatcher
- 用
runCurrent()触发协程执行
修改后的测试代码:
@Test fun `test my makeBackgroundCallAndClose`() = runTest(testDispatcher) { coEvery { interactor.doBackground(any()) } just runs val viewModel = MyViewModel( interactor, backgroundDispatcher = testDispatcher ) viewModel.makeBackgroundCallAndClose() runCurrent() // 执行testDispatcher上所有待处理的协程任务 coVerify(exactly = 1) { interactor.doBackground(null) } }
3. 替代方案(不修改ViewModel构造)
如果不想改动ViewModel代码,可以通过测试框架强制替换默认Dispatcher:
@Test fun `test my makeBackgroundCallAndClose`() = runTest(testDispatcher) { coEvery { interactor.doBackground(any()) } just runs // 强制将IO Dispatcher替换为测试Dispatcher Dispatchers.setIo(testDispatcher) val viewModel = MyViewModel(interactor, TestScope(testDispatcher)) viewModel.makeBackgroundCallAndClose() runCurrent() coVerify(exactly = 1) { interactor.doBackground(null) } // 测试结束后恢复默认Dispatcher Dispatchers.resetIo() }
内容的提问来源于stack exchange,提问作者testivanivan
相关产品推荐
相关产品推荐

