如何在单元测试中使用Spock Stub/替换父类方法
如何在Spock测试中Stub子类的super.methodWithSuper调用
你遇到的核心问题是:子类ExampleClazz的methodWithSuper方法中显式调用了父类ExtendableClazz的同名方法,而你希望保留子类方法的原有逻辑,仅替换父类方法的实现,而非完全重写子类方法。
以下是两种可行的解决方案:
方案1:使用Groovy元编程临时替换父类方法
利用Groovy的动态特性,临时修改父类ExtendableClazz的methodWithSuper实现,测试完成后恢复原方法,避免影响其他测试用例。这种方法无需修改生产代码,也不会耦合业务逻辑。
测试代码示例:
package com.foo import spock.lang.Specification class ExampleClazzTest extends Specification { def "makeString #inputStr"() { given: // 保存父类原方法的引用,用于测试后恢复 def originalMethod = ExtendableClazz.metaClass.getMetaMethod('methodWithSuper', String) // 替换父类方法为Stub实现 ExtendableClazz.metaClass.methodWithSuper = { String str -> return " STUB:" + str } ExampleClazz clazz = new ExampleClazz() expect: clazz.methodWithSuper(inputStr) == result cleanup: // 测试结束后恢复父类原方法,避免污染其他测试 ExtendableClazz.metaClass.methodWithSuper = originalMethod where: inputStr || result "foo" || "C:foo A:foo STUB:foo" "bar" || "C:bar A:bar STUB:bar" } }
方案2:创建匿名子类重写父类方法(不推荐)
通过创建ExampleClazz的匿名子类,重写爷爷类ExtendableClazz的methodWithSuper方法。当ExampleClazz调用super.methodWithSuper时,会优先调用匿名子类中的Stub实现。
测试代码示例:
package com.foo import spock.lang.Specification class ExampleClazzTest extends Specification { def "makeString #inputStr"() { when: ExampleClazz clazz = new ExampleClazz() { // 重写ExtendableClazz的methodWithSuper方法 @Override String methodWithSuper(String str) { return " STUB:" + str } } then: clazz.methodWithSuper(inputStr) == result where: inputStr || result "foo" || "C:foo A:foo STUB:foo" "bar" || "C:bar A:bar STUB:bar" } }
注意:这种方法依赖于Java的继承链机制,若后续生产代码中
ExampleClazz的继承关系变更,测试可能失效,且测试逻辑和生产代码耦合度较高,维护成本大,因此不推荐使用。
内容的提问来源于stack exchange,提问作者Jim
相关产品推荐
相关产品推荐

