You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用JUnit Mock测试Controller与Service层的新增记录方法?

问题描述

我想给Service层和Repository中新增数据库记录的方法编写Mock单元测试,但不知道正确操作方式,还遇到了报错。

现有代码

Controller代码

@PostMapping("/altaDiaInhabil")
private void addWorkingDay(@RequestBody CatDiaEntity day) throws Exception {
    try {
        catDiaInhabilService.addNewWorkingDay(day);
    } catch (Exception e) {
        LOGGER.error("Error in CatDiaEntity Values ");
        throw e;
    }
}

ServiceImpl代码

@Transactional
@Override
public void addNewWorkingDay(CatDiaEntity dayOff) throws Exception {
    try {
        catDiaRepository.saveWorkingDay(dayOff.getFechaInb(), dayOff.getDescDiaInb(),
                dayOff.getInhaMx(), dayOff.getInhabCh());

    } catch (Exception e) {
        LOGGER.error("An error ocurred to insert CatDiaEntity Data");

    }
}

遇到的报错

The method when in the type Mockito is not applicable for the arguments void

我编写的测试代码

@Mock
private CatDiaRepository catDiaRepository;

@InjectMocks
private CatDiaServiceImpl serviceImpl;

@BeforeEach
public void init() {
    MockitoAnnotations.openMocks(this);
    catDiEnatity = new CatDiaEntity();

}
@Test
public void testAddNewRecord() {
    catDiEnatity.setFechaInb("12/12/24");
    catDiEnatity.setDescDiaInb("New day");
    catDiEnatity.setInhaMx("1");
    catDiEnatity.setInhabCh("0");
    
    Mockito.when(catDiaRepository.saveWorkingDay(catDiEnatity.getFechaInb(), catDiEnatity.getDescDiaInb(), 
            catDiEnatity.getInhaMx(), catDiEnatity.getInhabCh())).thenReturn();
}

请问如何正确测试这两个方法?


解决方案

一、Service层单元测试(解决报错)

报错原因是saveWorkingDay是**无返回值(void)**方法,Mockito的when()只适用于有返回值的方法。针对void方法,需改用doNothing()或doThrow()来模拟行为:

正确的Service测试代码

@Mock
private CatDiaRepository catDiaRepository;

@InjectMocks
private CatDiaServiceImpl serviceImpl;

private CatDiaEntity catDiaEntity;

@BeforeEach
public void init() {
    MockitoAnnotations.openMocks(this);
    catDiaEntity = new CatDiaEntity();
}

@Test
public void testAddNewRecord_Success() throws Exception {
    // 准备测试数据
    catDiaEntity.setFechaInb("12/12/24");
    catDiaEntity.setDescDiaInb("New day");
    catDiaEntity.setInhaMx("1");
    catDiaEntity.setInhabCh("0");

    // 模拟Repository的void方法正常执行
    Mockito.doNothing().when(catDiaRepository)
            .saveWorkingDay(catDiaEntity.getFechaInb(), catDiaEntity.getDescDiaInb(),
                    catDiaEntity.getInhaMx(), catDiaEntity.getInhabCh());

    // 调用Service方法
    serviceImpl.addNewWorkingDay(catDiaEntity);

    // 验证Repository方法是否按预期调用
    Mockito.verify(catDiaRepository, Mockito.times(1))
            .saveWorkingDay("12/12/24", "New day", "1", "0");
}

// 可选:测试异常场景
@Test
public void testAddNewRecord_Exception() throws Exception {
    catDiaEntity.setFechaInb("12/12/24");
    // 模拟Repository抛出异常
    Mockito.doThrow(new RuntimeException("DB error")).when(catDiaRepository)
            .saveWorkingDay(anyString(), anyString(), anyString(), anyString());

    // 调用Service方法(内部会捕获异常)
    serviceImpl.addNewWorkingDay(catDiaEntity);

    // 验证Repository方法被调用
    Mockito.verify(catDiaRepository, Mockito.times(1))
            .saveWorkingDay("12/12/24", null, null, null);
}

核心说明:

  • doNothing():模拟void方法正常执行,无额外操作
  • verify():验证Mock对象的方法调用次数、参数匹配情况,这是void方法测试的核心验证逻辑
  • anyString()是Mockito参数匹配器,用于模糊匹配参数

二、Controller层单元测试

Controller层测试需用MockMvc模拟HTTP请求,同时Mock依赖的Service层:

Controller测试代码示例

@WebMvcTest(CatDiaController.class)
public class CatDiaControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private CatDiaInhabilService catDiaInhabilService;

    @Test
    public void testAddWorkingDay_Success() throws Exception {
        // 准备请求体数据
        CatDiaEntity requestBody = new CatDiaEntity();
        requestBody.setFechaInb("12/12/24");
        requestBody.setDescDiaInb("New day");
        requestBody.setInhaMx("1");
        requestBody.setInhabCh("0");

        // 模拟Service方法无异常执行
        Mockito.doNothing().when(catDiaInhabilService).addNewWorkingDay(requestBody);

        // 发送POST请求并验证响应
        mockMvc.perform(MockMvcRequestBuilders.post("/altaDiaInhabil")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(new ObjectMapper().writeValueAsString(requestBody)))
                .andExpect(MockMvcResultMatchers.status().isOk());

        // 验证Service方法被调用
        Mockito.verify(catDiaInhabilService, Mockito.times(1)).addNewWorkingDay(requestBody);
    }

    @Test
    public void testAddWorkingDay_Exception() throws Exception {
        CatDiaEntity requestBody = new CatDiaEntity();
        // 模拟Service抛出异常
        Mockito.doThrow(new Exception("Invalid data")).when(catDiaInhabilService).addNewWorkingDay(any(CatDiaEntity.class));

        // 发送请求并验证异常响应
        mockMvc.perform(MockMvcRequestBuilders.post("/altaDiaInhabil")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(new ObjectMapper().writeValueAsString(requestBody)))
                .andExpect(MockMvcResultMatchers.status().isInternalServerError());

        // 验证Service方法被调用
        Mockito.verify(catDiaInhabilService, Mockito.times(1)).addNewWorkingDay(requestBody);
    }
}

核心说明:

  • @WebMvcTest:专门用于Controller层测试,自动配置MockMvc
  • @MockBean:Mock Controller依赖的Service对象
  • MockMvc:模拟HTTP请求,验证响应状态、内容等

内容的提问来源于stack exchange,提问作者Root93

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 06:17:05