含@SpringBootTest时Mockito verify()方法失效的问题排查与解决
问题原因
同时用@SpringBootTest和@RunWith(MockitoJUnitRunner.class)会导致实例不匹配:
@SpringBootTest会启动完整Spring容器,Spring会自动创建MyService实例,并注入真实的CommonService(因为MyService用了@RequiredArgsConstructor,Spring会按类型查找依赖)。- 你用
@Mock创建的CommonService和@InjectMocks创建的MyService是Mockito独立管理的对象,和Spring容器里的实例完全是两个东西。 - 调试看到的
executeCommon执行,其实是Spring容器内的MyService调用了真实的CommonService,但你verify的是Mockito创建的Mock对象,自然会报“Wanted but not invoked”。
去掉@SpringBootTest后,Mockito完全接管测试,@InjectMocks直接创建MyService并注入你Mock的CommonService,调用和verify的是同一组实例,所以测试正常。
保留@SpringBootTest的解决方案
方案一:用@MockBean替换@Mock和@InjectMocks
@MockBean是Spring提供的注解,会把Mock对象注册到Spring容器中,这样Spring创建的MyService会自动注入这个Mock实例,确保调用和verify的是同一个对象:
@SpringBootTest public class MyServiceTest { @MockBean private CommonService commonService; @Autowired private MyService myService; @Test void shouldExecuteCommon() { myService.doService(); verify(commonService).executeCommon(any(), any()); } }
- 删掉
@RunWith(MockitoJUnitRunner.class)和setUp方法,Spring会自动处理Mock初始化。 - 通过
@Autowired获取Spring容器中的MyService实例,它依赖的CommonService就是你Mock的对象。
方案二:缩小Spring容器范围(更轻量)
如果不需要启动完整的Spring应用上下文,用@SpringJUnitConfig指定仅加载MyService相关配置,配合MockitoExtension:
@SpringJUnitConfig(classes = MyService.class) @ExtendWith(MockitoExtension.class) public class MyServiceTest { @MockBean private CommonService commonService; @Autowired private MyService myService; @Test void shouldExecuteCommon() { myService.doService(); verify(commonService).executeCommon(any(), any()); } }
这种方式只会创建必要的Bean,测试启动更快。
方案三:排除真实的CommonService自动配置
如果你的CommonService是通过Spring自动配置注册的,用@SpringBootTest的exclude属性排除对应的配置类,避免Spring创建真实实例:
@SpringBootTest(exclude = CommonServiceAutoConfiguration.class) public class MyServiceTest { @MockBean private CommonService commonService; @Autowired private MyService myService; @Test void shouldExecuteCommon() { myService.doService(); verify(commonService).executeCommon(any(), any()); } }
(注意替换成实际的自动配置类名称)
内容的提问来源于stack exchange,提问作者sunh
相关产品推荐
相关产品推荐

