带Mock的SpringBoot单元测试在IntelliJ正常,Maven执行失败
问题分析与解决方案
兄弟,我一眼就瞅出你这问题的根源了——你把Spring Boot的自动mock机制和Mockito手动初始化给混在一起用,结果俩玩意儿打架了!
核心问题
你用了@MockBean注解让Spring帮你管理mock实例,同时又在@Before方法里手动调用MockitoAnnotations.initMocks(this)创建了另一套mock对象。这就导致:
- Service里注入的是Spring上下文管理的mock实例
- 你在
verify时用的却是手动初始化的那个实例
两者根本不是同一个对象,自然就会抛出UnfinishedVerificationException。至于IDEA和Maven运行结果不一样,是因为两者的测试上下文加载机制略有差异,IDEA里偶然让实例“凑”成了同一个,但Maven下直接暴露了这个矛盾。
解决方案
直接删掉手动初始化的代码,完全交给Spring来处理mock即可:
@RunWith(SpringRunner.class) @ActiveProfiles("test") @SpringBootTest(classes = MainApplication.class) public class ServiceTest { @Autowired private IService service; // 变量名建议小写,符合Java编码规范 @MockBean private IDAO dao; @MockBean private ISearchDAO searchDAO; // 删掉原来的setUp方法和mockInitialized静态变量 @Test public void getByIdPersists() throws Exception { DTO dto = new DTO(1, "test"); when(dao.getById(1)).thenReturn(dto); DTO found = service.getById(1); verify(dao).getById(1); assertEquals(dto, found); } }
额外建议
- 别用静态变量控制测试状态:你之前的
mockInitialized静态变量是个大坑,测试框架可能会复用测试类实例,静态变量的状态会残留到下一个测试方法,导致各种不可预期的问题。 - 轻量测试可选MockitoExtension:如果你的测试不需要完整启动Spring上下文(比如只测Service层逻辑),可以用更轻量的纯Mockito方案,避免Spring上下文带来的复杂问题:
@ExtendWith(MockitoExtension.class) @ActiveProfiles("test") public class ServiceTest { @InjectMocks private IService service; @Mock private IDAO dao; @Mock private ISearchDAO searchDAO; @Test public void getByIdPersists() throws Exception { DTO dto = new DTO(1, "test"); when(dao.getById(1)).thenReturn(dto); DTO found = service.getById(1); verify(dao).getById(1); assertEquals(dto, found); } }
内容的提问来源于stack exchange,提问作者iton




