You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 07:14:59