如果通过启动(调度程序){...}调用CoroutineDispatcher,则如何测试该块是否在CoroutineDispatcher上运行

问题描述 投票:3回答:1

我们最近开始在Android应用程序上使用协同程序。一切都很好,花花公子,直到有人写了大致相当于以下功能的东西:

fun example(dispatcher: CoroutineDispatcher, block: () -> Unit) {
    launch(dispatcher) {
        block()
    }
}

我们想编写一个测试来验证使用block执行dispatcher

我们已经尝试了以下方法,但这不起作用,因为我们得到一个NullPointerException,因为dispatcher.parentContext没有被模拟。我不喜欢嘲笑它,因为我们不关心它执行的是什么上下文,只是它被执行了:

@Test
fun `test that doesn't work`() {
    val dispatcher: CoroutineDispatcher = mock()
    val block: () -> Unit = mock()

    // fails here, specifically on the call to `launch` in example()
    example(dispatcher, block)

    val captor = argumentCaptor<Runnable>()
    verify(dispatcher).dispatch(any(), captor.capture())
    verify(block, never()).invoke()

    captor.firstArgument.run()
    verify(block).invoke()
}

我们已经将此作为一种选择,但它仍然感觉不对:

@Test
fun `test that works but doesn't feel right`() {
    val executor: ExecutorService = mock()
    val block: () -> Unit = mock()

    example(executor.asCoroutineDispatcher(), block)

    val captor = argumentCaptor<Runnable>()
    verify(executor).execute(captor.capture())
    verify(block, never()).invoke()

    captor.firstArgument.run()
    verify(block).invoke()
}

任何人都能想出更好的东西吗?

编辑:

值得注意的依赖关系如下:

com.nhaarman:mockito-kotlin:1.5.0
org.jetbrains.kotlinx:kotlinx-coroutines-core:0.22.5
junit:junit:4.12
org.jetbrains.kotlin:kotlin-stdlib:1.2.30
kotlin executorservice kotlinx.coroutines
1个回答
0
投票

由于launch返回Job,您需要等待其完成才能验证已完成的任何事情。

你可以用两种方式做到这一点:

由于你是一个协同工具,你的实际单元测试可能会在启动执行完成之前完成。您需要等待其执行以确保您的测试没有提前完成。您可以通过多种方式实现这一目标。

  1. 更改你的函数签名以从启动返回Job(例如launch。这样你就可以在fun example(dispatcher: CoroutineDispatcher, block: () -> Unit) = launch(dispatcher) { ...函数上调用.join()来等待它的完成。 保留一个内部example,并使用执行启动设置它,例如var exampleJob:Job? = null。这样,在您的测试中,您可以使用exampleJob = launch { ...}等待其完成并在之后进行验证。

奖金解决方案:

你也可以使用exampleJob.join()MockK你的单位测试。这样,您的单元测试等待验证完成。

© www.soinside.com 2019 - 2024. All rights reserved.