如何使用协程测试加载指示器(TestCoroutineScope已废弃):新版调度器暂停方法问询
适配新版协程测试框架:替代废弃的
TestCoroutineScope实现调度器暂停 我完全懂你的困扰——旧版的TestCoroutineScope和配套测试API确实已经被废弃,新版协程测试框架改用了更清晰的TestDispatcher体系,下面是适配新版的完整解决方案:
第一步:确保使用最新的协程测试依赖
首先确认你的项目中引入了1.6.0及以上版本的kotlinx-coroutines-test(以Gradle为例):
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3"
这个版本开始引入了全新的测试API,彻底替代了旧的TestCoroutineScope和TestCoroutineDispatcher。
第二步:重写MainCoroutineRule(新版)
旧版Rule依赖TestCoroutineScope的委托逻辑,新版我们直接用StandardTestDispatcher实现:
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.TestDispatcher import kotlinx.coroutines.test.resetMain import kotlinx.coroutines.test.setMain import org.junit.rules.TestWatcher import org.junit.runner.Description class MainCoroutineRule( val testDispatcher: TestDispatcher = StandardTestDispatcher() ) : TestWatcher() { override fun starting(description: Description?) { super.starting(description) // 将Main调度器替换为测试调度器 Dispatchers.setMain(testDispatcher) } override fun finished(description: Description?) { super.finished(description) // 重置Main调度器为原始值 Dispatchers.resetMain() } }
这里不再需要TestCoroutineScope的委托,直接通过TestDispatcher来控制协程执行流程。
第三步:修改测试用例实现调度器暂停/恢复
新版中,暂停和恢复调度器的操作需要通过TestDispatcher的scheduler属性完成,替代旧的pauseDispatcher()和resumeDispatcher()方法:
import kotlinx.coroutines.test.advanceUntilIdle import org.junit.Assert.assertThat import org.junit.Rule import org.junit.Test import org.hamcrest.CoreMatchers.`is` class StatisticsViewModelTest { @get:Rule val mainCoroutineRule = MainCoroutineRule() private val statisticsViewModel = StatisticsViewModel() // 根据你的实际ViewModel初始化方式调整 @Test fun loadTasks_loading() { // 暂停测试调度器,让所有协程暂时挂起 mainCoroutineRule.testDispatcher.scheduler.pause() // 触发ViewModel的刷新操作 statisticsViewModel.refresh() // 验证初始加载状态为true assertThat(statisticsViewModel.dataLoading.getOrAwaitValue(), `is`(true)) // 恢复调度器并执行所有挂起的协程任务 mainCoroutineRule.testDispatcher.scheduler.resume() // 确保所有挂起的异步操作完全完成(比单纯resume更可靠) mainCoroutineRule.testDispatcher.scheduler.advanceUntilIdle() // 验证加载状态变为false assertThat(statisticsViewModel.dataLoading.getOrAwaitValue(), `is`(false)) } }
更简洁的替代方案:使用runTest函数
如果你不想维护自定义Rule,新版框架提供了runTest函数,它会自动管理测试调度器和Main调度器的切换,代码更简洁:
import kotlinx.coroutines.test.runTest import org.junit.Assert.assertThat import org.junit.Test import org.hamcrest.CoreMatchers.`is` class StatisticsViewModelTest { @Test fun loadTasks_loading() = runTest { // 获取当前测试上下文的调度器 val testDispatcher = this.testDispatcher // 暂停调度器 testDispatcher.scheduler.pause() val statisticsViewModel = StatisticsViewModel() statisticsViewModel.refresh() assertThat(statisticsViewModel.dataLoading.getOrAwaitValue(), `is`(true)) // 恢复并完成所有挂起任务 testDispatcher.scheduler.resume() advanceUntilIdle() assertThat(statisticsViewModel.dataLoading.getOrAwaitValue(), `is`(false)) } }
核心变化说明
- 旧版的
TestCoroutineDispatcher被替换为StandardTestDispatcher(或UnconfinedTestDispatcher,按需选择) - 调度器的暂停/恢复通过
testDispatcher.scheduler.pause()和testDispatcher.scheduler.resume()实现 advanceUntilIdle()方法可以确保所有挂起的协程操作完全执行完毕,避免测试遗漏后续异步逻辑
内容的提问来源于stack exchange,提问作者Augusto Carmo
相关产品推荐
相关产品推荐

