如何在Spock中Mock被测类注入实例的实例方法?
问题解答:用Spock Spy Mock Micronaut Bean的实例方法
是的,你完全可以通过Spock的Spy来Mock被测类ClassUnderTest自己的isRunning实例方法,只是当前的写法存在几个细节问题,导致Mock逻辑没有生效。下面我来拆解问题并给出调整方案:
问题根源
你手动调用Spy(classUnderTest)的方式,和Micronaut的依赖注入代理机制产生了冲突。Micronaut的@Singleton Bean默认是代理对象,当你Spy这个代理时,方法调用会被转发到原始的真实实例,导致你的Stubbing逻辑没有被触发。此外,Spock中Spy的交互验证和Stubbing顺序也需要注意,确保Mock逻辑在方法执行前被正确绑定。
解决方案
方案一:用Spock的@Spy注解直接注入被测类
这种方式最适配Micronaut的测试场景,让Spock自动为注入的Bean创建Spy代理,无需手动调用Spy()方法:
class MyTestClass extends Specification { @Subject @Spy // 新增@Spy注解,让Spock代理这个注入的Bean @Inject ClassUnderTest classUnderTest Event sampleEvent = getMockEvent(); def "test1" () { given: // 提前设置Stubbing,确保调用isRunning时返回false classUnderTest.isRunning(_ as Long) >> false when: def res = classUnderTest.callTestMethod(sampleEvent) then: // 验证isRunning确实被调用了一次 1 * classUnderTest.isRunning(sampleEvent.id) res != null } def getMockEvent() { new Event(/* Some attributes here */) } }
方案二:手动创建实例并Spy(适合轻量测试场景)
如果不需要Micronaut注入完整依赖,可以手动创建被测类实例,Mock它的依赖后再Spy:
class MyTestClass extends Specification { Event sampleEvent = getMockEvent(); def "test1" () { given: // Mock依赖的class1Instance Class1 class1Mock = Mock() // 手动初始化被测类,注入Mock的依赖 ClassUnderTest classUnderTest = new ClassUnderTest(class1Instance: class1Mock) // 创建Spy实例 def classUnderTestSpy = Spy(classUnderTest) // 设置Stubbing逻辑 classUnderTestSpy.isRunning(_ as Long) >> false when: def res = classUnderTestSpy.callTestMethod(sampleEvent) then: 1 * classUnderTestSpy.isRunning(sampleEvent.id) res != null } def getMockEvent() { new Event(/* Some attributes here */) } }
关键注意点
- 确保
isRunning方法不是final的:Spock的Spy无法拦截final方法,你的代码中该方法是public非final,符合要求。 - 优先用方案一:如果测试需要依赖Micronaut的注入生态(比如读取配置值
${com.myapplication.property}),方案一能保留完整的Bean生命周期,测试更贴近真实场景。
内容的提问来源于stack exchange,提问作者suvodipMondal
相关产品推荐
相关产品推荐

