如何使用MockMvc与Mockito让Stub返回HTTP 500或400状态码?
问题:如何Mock第三方API返回HTTP 500/400响应以测试Spring控制器错误处理?
我正在测试一个调用第三方API的Spring控制器,希望编写JUnit测试来Stub/Mock该API,使其返回HTTP 500和400响应,以验证控制器的错误处理逻辑。作为Spring和自动化测试新手,我不清楚如何Stub这些HTTP 500响应。以下是我的正向测试类代码:
@ExtendWith(SpringExtension.class) @WebMvcTest @AutoConfigureMockMvc @TestPropertySource(locations = "classpath:application-cloud-stub.properties") @ContextConfiguration(classes = {...}) public class ControllerTest { @Autowired private MockMvc mockMvc; @MockBean private BisTechnicalChecksClient client; @Test public void TestMethod() throws Exception { ObjectMapper mapper = new ObjectMapper(); ObjectReader reader = mapper.reader().forType(new TypeReference<List<ClientsByAddrWithStartDateResponse>>() { }); ClientsByAddrWithStartDateRequest request = mapper.readValue(new File("request_controller.json"), ClientsByAddrWithStartDateRequest.class); List<ClientsByAddrWithStartDateResponse> response = reader.readValue(new File( "response_controller.json")); when(client.getClientsByAddrWithStartDate(any(ClientsByAddrWithStartDateRequest.class))) .thenReturn(response); MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders .post("get-clients-by-addr-with-start-date") .contentType(MediaType.APPLICATION_JSON_VALUE) .header("param1", "value1") .content(mapper .writer() .withDefaultPrettyPrinter() .writeValueAsString(request))) .andExpect(MockMvcResultMatchers.status().is2xxSuccessful()) .andReturn(); String stringResponse = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8); List<ClientsByAddrWithStartDateResponse> actualResponse = reader.readValue(stringResponse); List<ClientsByAddrWithStartDateResponse> expectResponse = reader.readValue(new File( "response_controller.json")); Assertions.assertThat(actualResponse).isEqualTo(expectResponse); } }
我尝试通过Stub方法返回预设的MockHttpServletResponse,但至今未成功。请问需要如何修改才能让Stub返回500/400状态码并正常工作?
解决方案
核心问题在于:你的BisTechnicalChecksClient调用第三方API时,遇到HTTP错误(500/400)不会返回MockHttpServletResponse,而是会抛出对应的异常(比如Spring的RestClientException子类)。你需要Mock这个client抛出对应异常,而不是返回错误响应对象。
1. 模拟HTTP 500(服务器内部错误)
当第三方API返回500时,BisTechnicalChecksClient通常会抛出HttpServerErrorException.InternalServerError。你可以用Mockito让Mock的client抛出这个异常:
@Test public void whenThirdPartyReturns500_thenControllerReturnsErrorStatus() throws Exception { ObjectMapper mapper = new ObjectMapper(); ClientsByAddrWithStartDateRequest request = mapper.readValue(new File("request_controller.json"), ClientsByAddrWithStartDateRequest.class); // 让client抛出500异常 when(client.getClientsByAddrWithStartDate(any(ClientsByAddrWithStartDateRequest.class))) .thenThrow(new HttpServerErrorException(HttpStatus.INTERNAL_SERVER_ERROR)); // 验证控制器返回的状态码(根据你的错误处理逻辑调整) mockMvc.perform(MockMvcRequestBuilders .post("get-clients-by-addr-with-start-date") .contentType(MediaType.APPLICATION_JSON_VALUE) .header("param1", "value1") .content(mapper.writeValueAsString(request))) .andExpect(MockMvcResultMatchers.status().isInternalServerError()) // 如果控制器返回错误响应体,可按需验证 // .andExpect(MockMvcResultMatchers.jsonPath("$.error").value("Internal Server Error")) .andReturn(); }
2. 模拟HTTP 400(客户端错误)
同理,第三方API返回400时,client会抛出HttpClientErrorException.BadRequest:
@Test public void whenThirdPartyReturns400_thenControllerReturnsErrorStatus() throws Exception { ObjectMapper mapper = new ObjectMapper(); ClientsByAddrWithStartDateRequest request = mapper.readValue(new File("request_controller.json"), ClientsByAddrWithStartDateRequest.class); // 让client抛出400异常 when(client.getClientsByAddrWithStartDate(any(ClientsByAddrWithStartDateRequest.class))) .thenThrow(new HttpClientErrorException(HttpStatus.BAD_REQUEST, "Invalid Request")); // 验证控制器返回的状态码 mockMvc.perform(MockMvcRequestBuilders .post("get-clients-by-addr-with-start-date") .contentType(MediaType.APPLICATION_JSON_VALUE) .header("param1", "value1") .content(mapper.writeValueAsString(request))) .andExpect(MockMvcResultMatchers.status().isBadRequest()) // 按需验证响应体 // .andExpect(MockMvcResultMatchers.jsonPath("$.message").value("Invalid Request")) .andReturn(); }
关键说明
- 如果你的
BisTechnicalChecksClient没有直接抛出Spring的HTTP异常,而是自定义了异常类型,需要调整Mockito抛出的异常为对应的自定义异常。 - 测试时要根据控制器的实际错误处理逻辑来断言返回的状态码和响应体,比如有些控制器会把第三方的500转换成自己的500,或者返回特定的错误JSON结构。
内容的提问来源于stack exchange,提问作者Gleb_Aquilon
相关产品推荐
相关产品推荐

