如何使用协程对 Kotlin-JS 代码进行单元测试?

How to unit-test Kotlin-JS code with coroutines?

我创建了一个多平台 Kotlin 项目(JVM 和 JS),声明了预期的 class 并实现了它:

// Common module:
expect class Request(/* ... */) {
    suspend fun loadText(): String
}

// JS implementation:
actual class Request actual constructor(/* ... */) {
    actual suspend fun loadText(): String = suspendCoroutine { continuation ->
        // ...
    }
}

现在我正在尝试使用 kotlin.test 进行单元测试,对于 JVM 平台,我只是像这样使用 runBlocking

@Test
fun sampleTest() {
    val req = Request(/* ... */)
    runBlocking { assertEquals( /* ... */ , req.loadText()) }
}

如果没有runBlocking,如何在JS平台上重现类似的功能?

Mb 已经晚了,但是有开放 issue 可以增加在 js-tests 中使用 suspend 函数的可能性(这个函数将透明地转换为 promise)

解决方法

可以在普通代码中定义:

expect fun runTest(block: suspend () -> Unit)

在 JVM 中实现

actual fun runTest(block: suspend () -> Unit) = runBlocking { block() }

在 JS 中

actual fun runTest(block: suspend () -> Unit): dynamic = promise { block() } 

我能够完成以下工作:

expect fun coTest(timeout: Duration = 30.seconds, block: suspend () -> Unit): Unit

// jvm
actual fun coTest(timeout: Duration, block: suspend () -> Unit) {
    runBlocking {
        withTimeout(timeout) {
            block.invoke()
        }
    }
}

// js
private val testScope = CoroutineScope(CoroutineName("test-scope"))
actual fun coTest(timeout: Duration, block: suspend () -> Unit): dynamic = testScope.async {
    withTimeout(timeout) {
        block.invoke()
    }
}.asPromise()

这会使用 async 在您选择的范围内启动一个 co-routine,然后您可以像承诺一样 return。

然后你像这样写一个测试:

@Test
fun myTest() = coTest {
  ...
}