使用 kotlin 协程时,如何对调用挂起函数的函数进行单元测试?

When using kotlin coroutines, how do I unit test a function that calls a suspend function?

我有一个class这样的

class SomeClass {
    fun someFun() {
        // ... Some synchronous code
        async {
            suspendfun() 
        }
    }

    private suspend fun suspendFun() {
         dependency.otherFun().await()
         // ... other code
    }
}

我想进行单元测试 someFun() 所以我写了一个如下所示的单元测试:

@Test
fun testSomeFun() {
    runBlocking {
        someClass.someFun()
    }

    // ... verifies & asserts
}

但这似乎不起作用,因为在 runBlocking 中的所有内容完成之前,runBlocking 不会真正阻止执行。如果我直接在 runBlocking 中测试 suspendFun(),它会按预期工作,但我希望能够一起测试 someFun()

知道如何使用同步代码和异步代码测试函数吗?

修复异步

实施后,您的 someFun() 将“触发并忘记” async 结果。因此,runBlocking 对该测试没有影响。

如果可能,制作someFun()returnasyncDeferred,然后在runBlocking中调用await就可以了。

fun someFun(): Deferred<Unit> {
    // ... Some synchronous code
    return async {
        suspendFun()
    }
}

然后测试:

runBlocking {
    SomeClass().someFun().await()
}

这个 是获取更多信息的好资源。

备选方案:使用启动

也可以避免 async 而使用 suspend 函数和 launch 创建的协程:

suspend fun someFun() {
    // ... Some synchronous code
    suspendFun()
}

private suspend fun suspendFun() {
    delay(1000)
    println("executed")
    // ... other code
}

测试使用 launch 并且外部 runBlocking 隐式等待其完成:

val myScope = GlobalScope
runBlocking {
    myScope.launch {
        SomeClass().someFun()
    }
}