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
相关产品推荐
相关产品推荐

