为何使用@SpyBean配置Mock时会触发真实方法调用?
@SpyBean配置Mock时真实方法触发的原因及解决办法
问题场景
业务类代码:
@Service class A(){ fun someMethod():String{ println("inside real method") return "result" } }
使用@SpyBean的测试代码:
@SpyBean private lateinit var a:A @Test fun test(){ println("before mock") Mockito.`when`(a.someMethod()).doReturn("mock_result") println("empty test ended") }
执行结果:
before mock
inside real method
empty test ended
替换为@MockBean后的测试代码:
@MockBean private lateinit var a:A @Test fun test(){ println("before mock") Mockito.`when`(a.someMethod()).doReturn("mock_result") println("empty test ended") }
执行结果:
before mock
empty test ended
核心疑问:明明未直接调用方法,仅配置Mock时,@SpyBean场景下真实方法就被触发,且尝试doReturn、thenReturn、doAnswer、thenAnswer均有此现象。
原因分析
这是Mockito中Spy和Mock的本质差异导致的:
- @MockBean 创建的是完全模拟对象,所有方法默认不会执行真实逻辑,仅返回默认值(如null、空集合等),所以配置
when(...).doReturn(...)时不会触发真实方法。 - @SpyBean 是对真实对象的包装(部分模拟),默认会执行真实方法逻辑。当使用
Mockito.when(a.someMethod()).doReturn(...)这种语法时,Mockito需要先调用一次真实的someMethod()来获取方法调用的“桩点”,才能完成后续的返回值替换配置,这就导致了真实方法被执行。
解决办法
要避免Spy场景下配置Mock时触发真实方法,换用**doReturn(...).when(...)的语法顺序**即可,这种方式不会预先调用真实方法:
@SpyBean private lateinit var a:A @Test fun test(){ println("before mock") Mockito.doReturn("mock_result").`when`(a).someMethod() println("empty test ended") }
调整后,真实方法不会被触发,执行结果与@MockBean场景一致。
内容的提问来源于stack exchange,提问作者beatrice
相关产品推荐
相关产品推荐

