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

添加yield()导致协程单元测试失败?如何测试可取消协作函数?

协程yield()导致单元测试失败的原因及解决方案

一、测试失败的核心原因

添加yield()后测试失败,本质是runBlockingTest与TestCoroutineDispatcher的虚拟时间调度机制导致的:

  • runBlockingTest会同步执行协程内的立即代码,但yield()会触发协程挂起,将后续的titleDao.insertTitle(...)任务排入TestCoroutineDispatcher的任务队列。
  • 默认情况下,runBlockingTest不会自动处理队列中挂起的任务,导致断言执行时,插入操作还未完成,最终断言失败。

二、带yield()的可取消协作函数的测试方案

1. 手动推进虚拟时间(适配老版测试API)

在调用目标函数后,调用advanceUntilIdle(),让TestCoroutineDispatcher执行所有排队的挂起任务:

@Test
fun whenRefreshTitleSuccess_insertsRows() = runBlockingTest() {
    val titleDao = TitleDaoFake("title")
    val subject = TitleRepository(
        network = MainNetworkFake("OK"),
        titleDao = titleDao,
        ioDispatcher = TestCoroutineDispatcher(),
    )
    subject.refreshTitle()
    advanceUntilIdle() // 触发所有挂起任务执行
    Truth.assertThat(titleDao.nextInsertedOrNull()).isEqualTo("OK")
}

2. 使用新版测试调度器(推荐)

如果使用Kotlin Coroutines 1.6.0+的新测试API,改用StandardTestDispatcher配合runTest,它会自动处理挂起任务的调度,无需手动推进:

@Test
fun whenRefreshTitleSuccess_insertsRows() = runTest {
    val titleDao = TitleDaoFake("title")
    val subject = TitleRepository(
        network = MainNetworkFake("OK"),
        titleDao = titleDao,
        ioDispatcher = StandardTestDispatcher(testScheduler),
    )
    subject.refreshTitle()
    Truth.assertThat(titleDao.nextInsertedOrNull()).isEqualTo("OK")
}

3. 测试协作取消逻辑

要验证yield()带来的可取消特性,可以在协程执行到yield()前取消任务,验证插入操作是否被终止:

@Test
fun whenRefreshTitleCancelled_doesNotInsertRows() = runBlockingTest() {
    val titleDao = TitleDaoFake("title")
    val subject = TitleRepository(
        network = MainNetworkFake("OK"),
        titleDao = titleDao,
        ioDispatcher = TestCoroutineDispatcher(),
    )
    val job = launch { subject.refreshTitle() }
    job.cancel() // 在yield()挂起点前取消协程
    advanceUntilIdle()
    Truth.assertThat(titleDao.nextInsertedOrNull()).isNull()
}

内容的提问来源于stack exchange,提问作者Mohammadreza Khahani

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 12:43:25