无法弄清楚如何使用 spock 模拟高阶函数。示例代码片段:
import jakarta.inject.Singleton
@Singleton
class SomeClass {
fun bar(function: () -> Unit) {
function()
}
}
@Singleton
class SomeOtherClass {
fun foo() {
println("foo")
}
}
@Singleton
class ClassUnderTest(
private val someClass: SomeClass,
private val someOtherClass: SomeOtherClass,
) {
fun test() {
// someOtherClass::foo type is KFunction0<Unit>
someClass.bar(someOtherClass::foo)
}
}
史波克测试:
class ClassUnderTestSpecification extends Specification {
def someClass = Mock(SomeClass)
def someOtherClass = Mock(SomeOtherClass)
def classUnderTest = new ClassUnderTest(someClass, someOtherClass)
def 'test class'() {
when:
classUnderTest.test()
then:
// someOtherClass::foo type is Groovy Closure
// fails, as it should be the Kotlin KFunction
1 * someClass.bar(someOtherClass::foo)
0 * _
}
}
正如代码片段中的几条注释所述,
someOtherClass::foo
在 Kotlin 代码 (KFunction) 和 Groovy/Spock (Groovy Closure) 之间返回不同。无论如何,我还没有找到获取实际的 KFunction 进行模拟的方法,它实际上应该只是对函数的引用,所以我觉得模拟不应该那么困难,我只是在这里遗漏了一些东西。
曾尝试将 Groovy 闭包转换为 KFunction,但没有成功(没想到它会起作用),尝试仅使用普通的
SomeOtherClass::foo
而不是特定的模拟实例,但仍然是 Groovy 闭包,等等。所有路径都有引导至:
Too many invocations for:
0 * _ (1 invocation)
Matching invocations (ordered by last occurrence):
1 * someClass.bar(fun com.example.package.SomeOtherClass.foo(): kotlin.Unit) <-- this triggered the error
我不是 Kotlin 用户。起初,我想知道为什么我的错误消息与你的不同:
1 * someClass.bar(function foo (Kotlin reflection is not available)) <-- this triggered the error
原因解释如下这里:我必须添加
kotlin-reflect
作为我的示例 Kotlin 模块的依赖项。
不幸的是,Groovy 中似乎没有很好的方法来使用 Kotlin 函数引用。所以我们能做的就是
Function0<Unit>
和 toString()
输出。这是一个与不带
kotlin-reflect
的变体相匹配的变体:
import kotlin.Unit
import kotlin.jvm.functions.Function0
import spock.lang.Specification
class KotlinHigherOrderFunctionTest extends Specification {
def someClass = Mock(SomeClass)
def someOtherClass = Mock(SomeOtherClass)
def classUnderTest = new ClassUnderTest(someClass, someOtherClass)
def 'test class'() {
when:
classUnderTest.test()
then:
1 * someClass.bar(
{ it =~ /function foo |fun .*\.SomeOtherClass\.foo\(\): kotlin\.Unit/ } as Function0<Unit>
)
0 * _
}
}