Mockito.spy()为何仍调用真实方法?单元测试问题咨询
问题:Mockito Spy未拦截真实方法调用的原因与解决办法
需求与问题现象
单元测试核心需求:
- 方法
serviceMethod_1不调用真实逻辑,返回模拟值 - 方法
serviceMethod_2、serviceMethod_3保留真实调用逻辑
用户基于Mockito.spy()的定义(默认调用真实方法,仅对通过when(..)定义了模拟行为的方法做替换)编写测试,但运行后发现serviceMethod_1的真实方法仍被执行,控制台输出了该方法的日志内容。
原因分析
你当前使用的when(myServiceSpy.serviceMethod_1()).thenReturn(...)语法,对Spy对象存在一个关键限制:会先执行一次真实的方法调用,再将返回值替换为指定的模拟值。这是因为Spy是对真实对象的包装,常规when语法需要先获取方法的返回值才能完成存桩逻辑,因此不可避免触发真实方法执行。
解决方案
要彻底避免Spy调用serviceMethod_1的真实逻辑,需使用Mockito的doReturn(...).when(...)语法。这种方式直接绕过真实方法调用,直接为目标方法设置模拟返回值。
修改后的测试代码如下:
import org.mockito.Spy; import org.mockito.Mockito; import java.util.Arrays; import java.util.List; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @Spy private MyServiceImpl myServiceSpy; @Before public void setup() { System.out.println("SETUP"); } @Test public void myService_method_1_spy() { // 替换原when语法为doReturn语法,避免触发真实方法 Mockito.doReturn("call_serviceMethod_1_MOCK") .when(myServiceSpy).serviceMethod_1(); List<String> actualList = myServiceSpy.performService(); List<String> expectedList = Arrays.asList( "call_serviceMethod_1_MOCK", "call_serviceMethod_2_REAL", "call_serviceMethod_3_REAL"); assertEquals(expectedList, actualList); verify(myServiceSpy, times(1)).serviceMethod_1(); }
修改后运行测试,serviceMethod_1的真实逻辑不会被执行,控制台不会输出该方法的日志,同时performService会返回包含模拟值的预期列表。
内容的提问来源于stack exchange,提问作者Alexei
相关产品推荐
相关产品推荐

