Spock测试中Kotlin类的GroovySpy在Java类中失效问题
问题场景
用Groovy+Spock做单元测试时,设置reader.get(_ as Path, _ as String) >> fileA后,期望Java实现的Factory类调用reader.get()返回fileA,但实际执行了Kotlin Reader类的真实方法返回fileB。测试代码里直接调用factory.reader.get()能返回fileA,但Factory内部调用却不行。此前Mock Java对象正常,怀疑是Kotlin类导致该问题。
相关代码
测试代码(Groovy+Spock)
given: def reader = GroovySpy(Reader) def file = new File() reader.get() >> file // 此处file对应fileA and: def factory = new Factory(reader) when: ...
Kotlin实现的Reader类
class Reader( private val repoConfig: FactStoreRepoConfiguration = FactStoreRepoConfiguration() ) { fun get(): File { // 默认返回fileB的逻辑 } }
Java实现的Factory类
public final class Factory implements StoreFactory { private final Reader reader; public Store create() { System.out.println(reader.get()); // 期望输出fileA,实际输出fileB return new Store(reader); } }
问题原因
Kotlin中默认所有类和方法都是final的,而Spock的GroovySpy默认只能mock非final方法。Java是静态编译语言,调用final方法时不会走Groovy的动态代理逻辑,直接执行原方法;而测试代码中用Groovy直接调用时,会通过动态派发触发mock逻辑,所以能返回预期值。
解决方法
有两种可行方案:
修改Kotlin类,将方法改为可继承
在Reader类的get()方法前添加open关键字,允许方法被代理:class Reader( private val repoConfig: FactStoreRepoConfiguration = FactStoreRepoConfiguration() ) { open fun get(): File { // 默认返回fileB的逻辑 } }用Spock原生
Mock()替代GroovySpy
Spock的Mock()依赖Objenesis可以创建final类的代理,无需修改Kotlin源码:given: def reader = Mock(Reader) def file = new File() 1 * reader.get() >> file // 明确指定调用次数与返回值 and: def factory = new Factory(reader) when: factory.create() then: // 验证逻辑
内容的提问来源于stack exchange,提问作者abicuagb
相关产品推荐
相关产品推荐

