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

Spring MVC+JUnit+Mockito场景下,如何Mock@InjectMocks类内部方法?

解决Mockito中Mock@InjectMocks实例内部方法的问题

我来帮你搞定这个问题——你现在的核心误区是没搞清楚@InjectMocks、@Mock和@Spy之间的关系,咱们一步步拆解:

先分析你当前代码的问题

你声明了两个完全独立的Foo实例:

  • fooInstance是@InjectMocks创建的真实Foo对象,所有方法默认走真实实现
  • fooInstanceMock是@Mock创建的完全模拟的Foo对象,和真实实例没有任何关联

所以当你调用fooInstance.X()时,内部调用的是它自己的Y()方法,和你Mock的fooInstanceMock.Y()半毛钱关系都没有,自然会走真实逻辑,达不到你想要的效果。

正确的解决方案:用@Spy包装真实实例

要Mock对象内部的方法,你需要用@Spy来包装真实实例——Spy的作用就是保留对象的真实行为,同时允许你Mock指定的方法。之前你尝试Spy报错,大概率是用法不对,下面给你两种靠谱的写法:

写法一:结合@Spy和@InjectMocks(适用于Foo有其他依赖需要注入的场景)

如果Foo类里有其他依赖(比如用@Autowired注入的服务),可以用@InjectMocks配合@Spy来注入依赖并包装成Spy:

public class FooTest {
    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
    }

    // 如果Foo有@Mock注解的依赖,@InjectMocks会自动注入到这个Spy实例中
    @Spy
    @InjectMocks
    Foo fooSpy;

    @Test
    public void xTest() {
        // 关键:用doReturn语法Stub方法,避免触发真实的Y()调用
        doReturn(true).when(fooSpy).Y(/* 替换成你的方法参数 */);
        
        Boolean result = fooSpy.X(25);
        Assert.assertTrue(result);
    }
}

写法二:手动创建Spy(适用于Foo无其他依赖的场景)

如果Foo没有需要注入的依赖,直接手动创建真实实例再包装成Spy更简单:

public class FooTest {
    private Foo fooSpy;

    @Before
    public void setUp() throws Exception {
        Foo realFoo = new Foo(); // 创建真实的Foo实例
        fooSpy = Mockito.spy(realFoo); // 把真实实例包装成Spy
    }

    @Test
    public void xTest() {
        doReturn(true).when(fooSpy).Y(/* 替换成你的方法参数 */);
        Boolean result = fooSpy.X(25);
        Assert.assertTrue(result);
    }
}

为什么要用doReturn而不是when(...).thenReturn(...)?

这里要注意一个细节:当你Mock Spy对象的方法时,when(fooSpy.Y()).thenReturn(true)会先执行一次真实的Y()方法,再设置返回值;而doReturn(true).when(fooSpy).Y()是直接指定返回值,不会触发真实方法调用。这也是很多人用Spy时踩坑的点,所以推荐用doReturn语法来Stub Spy的方法。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 07:20:58