我有以下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)
}
其中it
是kotlin.coroutines.Continuation
对象