JUnit5 Mockito测试如何让被Mock类方法真实调用内部依赖
问题场景
现有三层Spring依赖类结构如下:
Class A (test) . -> Autowired B . -> Autowired C A.method { b.method2(); } B.method2 { c.method3(); }
当前编写A类的单元测试,初始测试代码结构如下:
@InjectMocks A a; @Mock B b; // 测试逻辑中调用 a.method();
现存问题:由于B是@Mock标注的纯模拟对象,调用*b.method2()时默认不会执行任何内部逻辑,无法走到后续c.method3()*的调用。实际需要达成两个目标:
- 调用a.method()时,*b.method2()执行真实业务逻辑,最终触发对c.method3()*的调用
- 可以正常通过
Mockito.when(c.method3()).thenReturn(1);给*c.method3()*设置返回值存根
实现方案
该需求可以实现,核心是用Spy对象替代纯Mock的B实例,手动补全B的依赖注入即可,操作步骤如下:
- 将B字段上的
@Mock注解替换为@Spy注解。@Spy生成的包装对象默认会走对应方法的真实逻辑,只有被显式存根的方法才会执行模拟逻辑,刚好满足b.method2()走真实代码的需求。 - 给依赖C添加
@Mock注解,让C成为Mockito管控的模拟对象,支持后续存根设置。 - 手动完成B对C的依赖注入:
@InjectMocks只会自动注入A的依赖,不会给Spy包装的B注入它依赖的C实例,需要在测试初始化方法中通过反射工具注入即可,一般用Spring Test自带的ReflectionTestUtils就可以实现。 - 正常对c.method3()做返回值存根,不需要额外存根b.method2(),调用时会自动执行B的真实逻辑,内部调用到c.method3()时就会返回预设的存根值。
完整测试代码参考:
@InjectMocks A a; @Spy B b; @Mock C c; @BeforeEach // JUnit4环境替换为@Before注解 void setUp() { // 把Mock生成的C实例注入到Spy的B对象中 ReflectionTestUtils.setField(b, "c", c); // 设置c.method3()的存根返回值 Mockito.when(c.method3()).thenReturn(1); } @Test void testAMethod() { // 执行被测方法 a.method(); // 可按需添加断言、调用验证逻辑 Mockito.verify(c, Mockito.times(1)).method3(); }
补充说明:如果后续部分用例需要b.method2()不走真实逻辑,直接用Mockito给b.method2()单独做存根即可,Spy对象支持对单个方法做模拟覆盖,灵活性比纯Mock对象更高。
内容的提问来源于stack exchange,提问作者ishallwin
相关产品推荐
相关产品推荐

