You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

带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);
    }
}

额外建议

  1. 别用静态变量控制测试状态:你之前的mockInitialized静态变量是个大坑,测试框架可能会复用测试类实例,静态变量的状态会残留到下一个测试方法,导致各种不可预期的问题。
  2. 轻量测试可选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

火山引擎 最新活动