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

如何使用协程测试加载指示器(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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 22:27:39