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

如何使用Mockito测试Repository中的InternalServerError?控制器POST接口失败测试返回415而非预期500的问题排查

解决Controller POST方法测试中的415和500断言问题

一、先解决415不支持媒体类型的问题

你遇到的第一个415错误,根源非常明确:你的失败测试请求没有指定Content-Type。

看你的成功测试代码,你明确添加了.contentType(MediaType.APPLICATION_JSON),但失败测试里只加了.accept(MediaType.APPLICATION_JSON)——accept是告诉服务器你接受什么类型的响应,而contentType才是告诉服务器你发送的请求体是什么类型。没有指定Content-Type的话,Spring无法解析你的JSON请求体,直接返回415错误。

修改失败测试的请求构建代码,补上contentType配置:

@Test
@DisplayName("POST /customers - Failure")
void createProductShouldFail() throws Exception {
    // Setup mocked service
    when(customerService.save(any(Customer.class))).thenThrow(HttpServerErrorException.InternalServerError.class);
    RequestBuilder requestBuilder = MockMvcRequestBuilders.post("/customers")
            .contentType(MediaType.APPLICATION_JSON) // 新增这一行
            .accept(MediaType.APPLICATION_JSON)
            .content("{\"name\":\"John\"}");
    MvcResult result=mockMvc.perform(requestBuilder).andReturn();
    MockHttpServletResponse response = result.getResponse();
    // Validate the response code and content type
    assertEquals(HttpStatus.INTERNAL_SERVER_ERROR.value(), response.getStatus());
}

二、解决添加注解后测试抛出异常的问题

你添加@RestController和@EnableWebMvc后出现NestedServletException,原因是:
你的控制器try-catch只捕获了URISyntaxException,但Mock的服务抛出的HttpServerErrorException.InternalServerError并没有被捕获,这个异常会被Spring的Servlet容器包装成NestedServletException抛出,导致测试在mockMvc.perform时直接报错,而不是得到预期的500响应。

要让控制器返回500状态码,有两种可行方案:

方案1:扩展控制器的异常捕获范围

修改控制器的catch块,把HttpServerErrorException也纳入捕获范围(或者直接捕获Exception,但更推荐精准捕获特定异常):

@PostMapping(path = "/customers")
public ResponseEntity<Customer> saveCustomer(@RequestBody Customer customer){
    try {
        Customer savedCustomer = customerService.save(customer);
        return ResponseEntity
                .created(new URI("/customers/" + savedCustomer.getId()))
                .body(savedCustomer);
    } catch (URISyntaxException | HttpServerErrorException e) { // 添加HttpServerErrorException
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
    }
}

方案2:利用Spring的默认异常处理器

如果你不想在控制器里手动捕获异常,Spring的默认异常处理器会自动把HttpServerErrorException这类Spring HTTP异常转换成对应的状态码响应。此时你可以把测试代码改成链式调用的方式,用andExpect直接断言状态码:

@Test
@DisplayName("POST /customers - Failure")
void createProductShouldFail() throws Exception {
    when(customerService.save(any(Customer.class))).thenThrow(HttpServerErrorException.InternalServerError.class);
    mockMvc.perform(MockMvcRequestBuilders.post("/customers")
            .contentType(MediaType.APPLICATION_JSON)
            .accept(MediaType.APPLICATION_JSON)
            .content("{\"name\":\"John\"}"))
            .andExpect(status().isInternalServerError()); // 直接断言状态码
}

三、验证断言是否生效的方法

要确认你的状态码断言是否正常工作,可以通过以下方式验证:

  1. 在测试中添加.andDo(print()),MockMvc会打印完整的请求和响应信息,你可以直观看到响应的状态码:
    mockMvc.perform(requestBuilder)
           .andDo(print())
           .andExpect(status().isInternalServerError());
    
  2. 如果用原来的andReturn()方式获取响应,可以打印response.getStatus()的值,直接确认实际返回的状态码:
    MockHttpServletResponse response = result.getResponse();
    System.out.println("实际响应状态码:" + response.getStatus()); // 打印验证
    assertEquals(HttpStatus.INTERNAL_SERVER_ERROR.value(), response.getStatus());
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 06:56:53