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

JUnit Mockito测试:如何真实调用methodOne并Mock methodTwo

解决Mockito Spy中真实调用methodOne但Mock methodTwo的问题

我完全懂你遇到的这个坑——用Spy对象时明明想让methodOne真实跑起来,同时mock掉它调用的methodTwo,结果反而methodOne直接跳过执行,直奔断言环节。这其实是Mockito Spy的一个常见误区,咱们一步步拆解解决:

先明确你的业务类场景

假设你的FooService大概是这样的:

public class FooService {
    public String methodOne() {
        // 这里是你要真实执行的业务逻辑
        String subResult = methodTwo();
        return "methodOne最终结果: " + subResult;
    }

    public String methodTwo() {
        // 这是你想mock的依赖方法,可能有外部调用或耗时逻辑
        return "真实methodTwo的返回值";
    }
}

错误写法的问题根源

很多人会下意识这么写测试,但这就是导致methodOne不执行的原因:

@Test
public void testMethodOneWrong() {
    FooService spyFoo = Mockito.spy(new FooService());
    // 这里的问题:when(spyFoo.methodTwo())会先触发一次真实的methodTwo调用,甚至可能打断后续流程
    when(spyFoo.methodTwo()).thenReturn("mock的methodTwo返回值");
    
    String result = spyFoo.methodOne();
    assertEquals("methodOne最终结果: mock的methodTwo返回值", result);
}

为什么失效?因为用when(spy.xxx()).thenReturn(...)处理Spy对象时,Mockito会先执行一次真实的xxx()方法;更关键的是,如果methodOne里调用的是this.methodTwo(),原始对象的方法调用可能绕开Spy代理,导致mock逻辑不生效,甚至如果methodTwo抛出异常,直接中断methodOne的执行。

正确的测试实现方式

核心是用doReturn().when()来mock Spy的方法,既不会触发真实方法调用,又能确保Spy代理拦截到methodOne内部对methodTwo的调用:

import org.junit.Test;
import org.mockito.Mockito;
import static org.junit.Assert.assertEquals;

public class FooServiceTest {

    @Test
    public void testMethodOneCorrect() {
        // 1. 创建基于真实实例的Spy对象
        FooService spyFoo = Mockito.spy(new FooService());
        
        // 2. 用doReturn安全mock methodTwo,不会触发真实调用
        Mockito.doReturn("mock的methodTwo返回值")
               .when(spyFoo)
               .methodTwo();
        
        // 3. 真实调用methodOne,此时内部的methodTwo会被mock拦截
        String actualResult = spyFoo.methodOne();
        
        // 4. 验证结果是否符合预期
        String expectedResult = "methodOne最终结果: mock的methodTwo返回值";
        assertEquals(expectedResult, actualResult);
        
        // 可选:验证methodTwo确实被methodOne调用了一次
        Mockito.verify(spyFoo, Mockito.times(1)).methodTwo();
    }
}

关键逻辑说明

  • doReturn().when()是Mockito为Spy对象设计的安全mock方式,它不像when().thenReturn()那样先执行真实方法,避免了不必要的副作用。
  • 当你调用spyFoo.methodOne()时,Spy代理会接管这个调用,执行真实的methodOne逻辑;而methodOne内部调用this.methodTwo()时,this此时是Spy代理对象(不是原始的FooService实例),所以会被Mockito拦截,返回你预设的mock值。

这样就能完美满足你的需求:真实执行methodOne,同时mock掉它依赖的methodTwo返回值。

内容的提问来源于stack exchange,提问作者Richard

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:48:17