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

use*_*913 23 unit-testing coroutine kotlin kotlin-coroutines

我有这样的课

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

    private suspend fun suspendFun() {
         dependency.otherFun().await()
         // ... other code
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

    // ... verifies & asserts
}
Run Code Online (Sandbox Code Playgroud)

但这似乎不起作用,因为runBlocking实际上不会阻止执行,直到runBlocking内的所有内容都完成.如果我suspendFun()直接在里面测试runBlocking它按预期工作,但我希望能够一起测试someFun().

有关如何使用同步和异步代码测试函数的任何线索?

s1m*_*nw1 13

修复异步

实施后,您的someFun()意志就是"解雇并忘记" async结果.结果,runBlocking在该测试中没有区别.

如果可能的话,请someFun()回报asyncDeferred,然后在runBlocking,呼吁await就可以了.

fun someFun(): Deferred<Unit> {
    // ... Some synchronous code
    return async {
        suspendFun()
    }
}
Run Code Online (Sandbox Code Playgroud)

然后测试:

runBlocking {
    SomeClass().someFun().await()
}
Run Code Online (Sandbox Code Playgroud)

这个问题/答案是获取进一步信息的良好资源.

替代方案:使用启动

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

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

private suspend fun suspendFun() {
    delay(1000)
    println("executed")
    // ... other code
}
Run Code Online (Sandbox Code Playgroud)

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

val myScope = GlobalScope
runBlocking {
    myScope.launch {
        SomeClass().someFun()
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 如果忽略其返回值,则不应使用`async`.你应该使用`launch`,这样你就会在恢复线程中抛出未处理的异常. (3认同)
  • 为什么`runBlocking {launch {...} .join()}`?你不能只使用`runBlocking {...}`吗? (3认同)