在 Android 上测试 Kotlin 协程

官方文档

https://developer.android.google.cn/kotlin/coroutines/test?hl=zh-cn
API 是 kotlinx.coroutines.test 库的一部分。如需访问这些 API,请务必添加相应工件作为项目的测试依赖项。

dependencies {
    testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version"
}

在测试中调用挂起函数

如需在测试中调用挂起函数,您必须位于协程中。由于 JUnit 测试函数本身并不是挂起函数,因此您需要在测试中调用协程构建器以启动新的协程。

suspend fun fetchData(): String {
    delay(1000L)
    return "Hello world"
}

@Test
fun dataShouldBeHelloWorld() = runTest {
    val data = fetchData()
    assertEquals("Hello world", data)
}

TestDispatchers

TestDispatchers 是用于测试的 CoroutineDispatcher 实现。如果要在测试期间创建新的协程,您需要使用 TestDispatchers,以使新协程的执行可预测。

注意:新协程可直接在测试主体中创建,也可在测试中所调用的任何代码中创建(例如在测试的对象中)。
TestDispatcher 有两种可用的实现:StandardTestDispatcher 和 UnconfinedTestDispatcher,可分别对新启动的协程执行不同的调度。两者都使用 TestCoroutineScheduler 来控制虚拟时间并管理测试中正在运行的协程。

一个测试中只能使用一个调度器实例,且所有 TestDispatchers 应共用该调度器。如需了解如何共用调度器,请参阅注入测试调度程序。

为了启动顶级测试协程,runTest 会创建一个 TestScope,它是 CoroutineScope 的实现,将始终使用 TestDispatcher。如果未指定,TestScope 将默认创建 StandardTestDispatcher,并将其用于运行顶级测试协程。

StandardTestDispatcher

@Test
fun standardTest() = runTest {
    val userRepo = UserRepository()

    launch { userRepo.register("Alice") }
    launch { userRepo.register("Bob") }

    assertEquals(listOf("Alice", "Bob"), userRepo.getAllUsers()) // ❌ Fails
}

可通过多种方式让出测试协程,以让排队的协程运行。所有以下调用都可在返回之前让其他协程在测试线程上运行:

advanceUntilIdle:在调度器上运行所有其他协程,直到队列中没有任何内容。这是一个不错的默认选择,可让所有待处理的协程运行,适用于大多数测试场景。
advanceTimeBy:将虚拟时间提前指定时长,并运行已调度为在该虚拟时间点之前运行的所有协程。
runCurrent:运行已调度为在当前虚拟时间运行的协程。

UnconfinedTestDispatcher

如果在 UnconfinedTestDispatcher 上启动新协程,系统会在当前线程上快速启动。也就是说,这些协程会立即开始运行,而不会等待其协程构建器返回。在许多情况下,这种调度行为会使测试代码更加简单,因为您无需手动让出测试线程即可让新协程运行。

@Test
fun unconfinedTest() = runTest(UnconfinedTestDispatcher()) {
    val userRepo = UserRepository()

    launch { userRepo.register("Alice") }
    launch { userRepo.register("Bob") }

    assertEquals(listOf("Alice", "Bob"), userRepo.getAllUsers()) // ✅ Passes
}

注入测试调度程序

设置主调度程序

在本地单元测试中,封装 Android 界面线程的 Main 调度程序将无法使用,因为这些测试是在本地 JVM 而不是 Android 设备上执行的。如果被测试代码引用主线程,它会在单元测试期间抛出异常。

在测试之外创建调度程序

class Repository(private val ioDispatcher: CoroutineDispatcher) { /* ... */ }

class RepositoryTestWithRule {
    private val repository = Repository(/* What TestDispatcher? */)

    @get:Rule
    val mainDispatcherRule = MainDispatcherRule()

    @Test
    fun someRepositoryTest() = runTest {
        // Test the repository...
        // ...
    }
}

创建您自己的 TestScope

class SimpleExampleTest {
    val testScope = TestScope() // Creates a StandardTestDispatcher

    @Test
    fun someTest() = testScope.runTest {
        // ...
    }
}

注入作用域

如果有类创建需要您在测试期间控制的协程,则可以将协程作用域注入到该类中,并在测试中将其替换为 TestScope

class UserState(
    private val userRepository: UserRepository,
    private val scope: CoroutineScope,
) {
    private val _users = MutableStateFlow(emptyList<String>())
    val users: StateFlow<List<String>> = _users.asStateFlow()

    fun registerUser(name: String) {
        scope.launch {
            userRepository.register(name)
            _users.update { userRepository.getAllUsers() }
        }
    }
}
class UserStateTest {
    @Test
    fun addUserTest() = runTest { // this: TestScope
        val repository = FakeUserRepository()
        val userState = UserState(repository, scope = this)

        userState.registerUser("Mona")
        advanceUntilIdle() // Let the coroutine complete and changes propagate

        assertEquals(listOf("Mona"), userState.users.value)
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
为了满足广大Android开发爱好者与从业者的学习需求,我们精心整理并上传了一份全面而实用的Android项目资源包。这份资源包内容丰富,涵盖了从基础知识到实战应用的全方位内容,旨在为开发者们提供一个便捷、高效的学习平台。 一、文件手册 资源包中的文件手册部分,详细记录了Android开发的核心知识点和常用技术。无论是初学者还是有一定经验的开发者,都能从中找到所需的学习资料。手册采用了简洁明了的排版方式,使得查阅更加方便快捷。同时,手册内容深入浅出,既适合新手入门,也能为老手提供有价值的参考。 二、项目实战与练习 为了让学习者能够将理论知识与实践相结合,我们特别准备了项目实战与练习部分。这部分内容包含了多个精心设计的Android项目案例,从需求分析、设计思路到实现过程,都有详细的讲解和代码示例。学习者可以通过实际操作,深入了解Android开发的整个流程,提升自己的实战能力。 此外,我们还提供了一系列练习题,旨在巩固所学知识,检验学习成果。这些练习题既有基础题,也有难度较高的挑战题,适合不同层次的学习者进行练习。 三、Android开发工具集 在Android开发过程中,选择合适的工具能够大大提高开发效率。因此,我们整理了常用的Android开发工具集,包括开发工具、测试工具、性能优化工具等。这些工具都是经过我们精心筛选和测试的,能够帮助开发者们更加高效地进行Android开发工作。 总的来说,这份Android项目资源包是一份不可多得的学习资料,无论你是初学者还是有一定经验的开发者,都能从中受益匪浅。我们希望通过这份资源包,为广大Android开发爱好者与从业者提供一个更加便捷、高效的学习平台,共同推动Android开发领域的发展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值