如何在Spock中Mock Kotlin高阶函数?
Spock测试Kotlin高阶函数的函数引用匹配问题
问题场景
在Kotlin代码中,someOtherClass::foo是KFunction0<Unit>类型,但在Groovy编写的Spock测试里,同样的语法会生成Groovy闭包,导致调用验证时类型不匹配,触发断言错误。
Kotlin业务代码
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 的类型为 KFunction0<Unit> someClass.bar(someOtherClass::foo) } }
Spock测试代码
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 的类型为 Groovy Closure // 验证失败,它应该是Kotlin的KFunction 1 * someClass.bar(someOtherClass::foo) 0 * _ } }
触发的错误信息
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
解决方案
方案1:使用类型匹配器
不精确匹配函数引用实例,而是匹配其类型,适合只需要验证调用次数和参数类型的场景:
then: 1 * someClass.bar(_ instanceOf kotlin.jvm.functions.Function0) 0 * _
方案2:验证函数引用的属性
如果需要确认是指定函数的引用,可以检查函数名称等属性,避免实例不匹配的问题:
then: 1 * someClass.bar({ it.name == "foo" }) 0 * _
方案3:在Kotlin中封装函数引用获取
在SomeOtherClass中添加方法返回绑定到实例的函数引用,统一业务代码和测试代码的获取方式:
修改Kotlin的SomeOtherClass:
@Singleton class SomeOtherClass { fun foo() { println("foo") } fun getFooFunction(): () -> Unit = this::foo }
修改ClassUnderTest的test方法:
fun test() { someClass.bar(someOtherClass.getFooFunction()) }
测试代码中直接调用封装方法匹配:
then: 1 * someClass.bar(someOtherClass.getFooFunction()) 0 * _
方案4:使用Kotlin类级函数引用(适用于无状态函数)
如果foo是无状态的,可以在Kotlin代码中改用类级函数引用,测试中同样使用类级引用匹配(因为类级函数引用在JVM上是单例):
修改ClassUnderTest的test方法:
fun test() { someClass.bar(SomeOtherClass::foo) }
测试代码中匹配类级引用:
then: 1 * someClass.bar(SomeOtherClass::foo) 0 * _
内容的提问来源于stack exchange,提问作者HoneTheRat
相关产品推荐
相关产品推荐

