我正在尝试使用mockk框架在我的一个单元测试中设置一个模拟,它执行一个挂起的函数,如下所示:
val executionCompletionSource = CompletableDeferred<Nothing>()
suspend fun task(): Unit = executionCompletionSource.await()
val mock = mockk<Executable> { coEvery { execute() } coAnswers { task() } }然而,我发现如果我在启动的协程作用域中调用mock.execute(),测试会无限期地挂起。如果我在启动的作用域中直接调用task(),测试运行得很好。
尽管mockk documentation确实谈到了一些协程模拟,但我找不到任何文档或示例来说明如何执行协程来响应对模拟的挂起函数的调用。
下面是一个演示这一点的SSCCE:
package experiment
import io.mockk.coEvery
import io.mockk.mockk
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlin.system.measureTimeMillis
interface Executable {
suspend fun execute()
}
fun main() {
val executionCompletionSource = CompletableDeferred<Nothing>()
suspend fun task(): Unit = executionCompletionSource.await()
val mock = mockk<Executable> { coEvery { execute() } coAnswers { task() } }
runBlocking {
val execution = launch { mock.execute() } // This blocks the test indefinitely
//val execution = launch { task() } // This works fine (~110-120 ms)
measureTimeMillis {
delay(100)
executionCompletionSource.cancel()
execution.join()
}.also { elapsed -> println("Elapsed in $elapsed ms") }
}
}使用以下依赖关系:
implementation(kotlin("stdlib-jdk8"))
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.0.0")
implementation("io.mockk:mockk:1.8.10.kotlin13")发布于 2018-11-09 20:47:51
这似乎是mockk处理协程的方式的错误-它现在是tracked here。
作为一种临时的解决办法,我在需要模拟挂起函数的情况下手动创建模拟。例如:
private fun generateDummyChildren(
numberOfChildren: Int = 5 /* sensible default */,
executionRoutine: suspend () -> Unit
): Iterable<ExecutableNode> {
fun createDummy(index: Int) = object: ExecutableNode {
override val id = "Dummy $index"
override suspend fun execute() = executionRoutine()
}
return Array(numberOfChildren, ::createDummy).asIterable()
}https://stackoverflow.com/questions/53223093
复制相似问题