如何使用Spock(groovy)测试kotlin suspend函数



我有以下kotlin暂停功能:

suspend fun registerNewTransaction(transaction: String): String

我试图通过Spock测试它,但我没有找到在不指定Continuation<? super String>参数的情况下调用这个kotlin挂起函数的方法,因为Groovy将kotlin容器类标识为Java类。我想知道是否可以从另一种基于JVM的语言调用挂起函数,否则我将不得不使用另一个测试库,如JUnit。

您可以模拟该Continuation对象,kotlin正在将其编译到方法调用中。这个代码对我有效:

// mocked continuation
def continuation = Mock(Continuation) {
getContext() >> Mock(CoroutineContext)
}
// method call which should be tested
subjectUnderTest.suspendableMethod(someParameter, continuation)

@julianwki的答案将在运行类似withContext(Dispatchers.IO) { /* ... /*/ }的程序后中断

一个更健壮的版本是使用实际的CoroutineContext运行,而不是嘲笑它:

def continuation = Mock(Continuation) {
getContext() >> Dispatchers.Default
}

我认为通过调用TestScopeKt.TestScope(EmptyCoroutineContext.INSTANCE)(org.jetbrains.kotlinx:kotlinx-coroutines-test(以某种方式创建Continuation是可能的,因为这似乎是底层runTest所使用的。然而,我最近找到了一个达到这一点的好方法。

还要注意,嘲笑Continuation,我们没有fun resumeWith(result: Result<T>)的实现,到目前为止,这似乎不是一个问题,但可能在未来。找到一个完全没有模拟的解决方案可能是可取的。

此外,如果从Groovy/Spock调用一个suspend函数,那么可能就不太幸运了。我确实尝试了上面建议的解决方案:在Java类中调用Kotlin suspend函数和类似的";黑客;如果直接从Groovy调用它们,则不会有任何运气。可以为所需的每个调用制作一个Kotlin包装器,然而,至少在我的情况下,它是不可行的

如果可以从另一个基于JVM的JVM调用挂起函数语言

这是可能的,但您需要将Continuation作为最后一个参数传递,因为这是Kotlin编译suspend函数的方式

我建议使用Kotlin来测试Kotlin代码,有很多特定于Kotlin的库,比如mockk,支持协同程序。

我用这个问题作为Java类中调用Kotlin suspend函数的参考并在我的代码中添加了这个功能

fun <T> await(block: suspend () -> T): T =
GlobalScope.future { block.invoke() }.get()

并以这种方式使用:

await {
myService.mySuspendedFunction(myArguments, it)
}

其中itkotlin.coroutines.Continuation对象

最新更新