如何为RestTemplate场景下含异常分支的if-else逻辑编写Junit测试用例
测试实现指导
前置准备
你需要用Mockito对RestTemplate进行打桩模拟,根据你的业务逻辑分支,分别模拟正常返回和抛出HttpStatusCodeException两种场景,验证对应分支的func方法是否被正确调用即可完成全量代码覆盖。
如果你的func1~func8是被测业务类自身的方法,需要对被测类使用@Spy注解,才能验证方法的调用情况;如果func是其他依赖类的方法,直接对对应依赖加@Mock注解即可。
分支覆盖梳理
你当前的逻辑一共包含8个可执行分支,逐个覆盖即可:
- 正常返回+low优先级:调用func1
- 正常返回+high优先级:调用func2
- 抛出503异常+low优先级:调用func3
- 抛出503异常+high优先级:调用func4
- 抛出403异常+low优先级:调用func5
- 抛出403异常+high优先级:调用func6
- 抛出其他状态码异常+low优先级:调用func7
- 抛出其他状态码异常+high优先级:调用func8
代码示例
测试类基础结构
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Spy; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.client.HttpStatusCodeException; import org.springframework.web.client.RestTemplate; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) public class 你的业务类名Test { @Mock private RestTemplate restTemplate; // 被测类用Spy注解才能验证自身方法的调用 @Spy @InjectMocks private 你的业务类名 targetService; // 替换为你业务类中someendpoint的实际值 private static final String TEST_ENDPOINT = "http://your-test-endpoint"; private final Request mockRequest = new Request(); private final HttpHeaders mockHeaders = new HttpHeaders(); }
正常返回场景用例
@Test void 正常返回_low优先级_调用func1() { // 打桩RestTemplate返回正常响应 ResponseEntity<Response> mockResp = ResponseEntity.ok(new Response()); when(restTemplate.postForEntity(eq(TEST_ENDPOINT), any(HttpEntity.class), eq(Response.class))) .thenReturn(mockResp); // 执行测试方法 targetService.processData(mockRequest, mockHeaders, "low"); // 验证分支逻辑正确 verify(targetService, times(1)).func1(); verify(targetService, never()).func2(); } @Test void 正常返回_high优先级_调用func2() { ResponseEntity<Response> mockResp = ResponseEntity.ok(new Response()); when(restTemplate.postForEntity(eq(TEST_ENDPOINT), any(HttpEntity.class), eq(Response.class))) .thenReturn(mockResp); targetService.processData(mockRequest, mockHeaders, "high"); verify(targetService, times(1)).func2(); verify(targetService, never()).func1(); }
异常返回场景用例
以503+low优先级为例,其他状态码的分支仅需修改异常的状态码返回值即可:
@Test void 抛503异常_low优先级_调用func3() { // 模拟HttpStatusCodeException返回503状态码 HttpStatusCodeException mockEx = mock(HttpStatusCodeException.class); when(mockEx.getStatusCode()).thenReturn(HttpStatus.SERVICE_UNAVAILABLE); // 打桩RestTemplate抛出异常 when(restTemplate.postForEntity(eq(TEST_ENDPOINT), any(HttpEntity.class), eq(Response.class))) .thenThrow(mockEx); targetService.processData(mockRequest, mockHeaders, "low"); verify(targetService, times(1)).func3(); }
其他状态码(非403、503)的场景需要额外模拟响应体,避免ObjectMapper解析失败:
@Test void 抛404异常_high优先级_调用func8() throws JsonProcessingException { HttpStatusCodeException mockEx = mock(HttpStatusCodeException.class); when(mockEx.getStatusCode()).thenReturn(HttpStatus.NOT_FOUND); // 构造合法的响应JSON串 String mockRespJson = new ObjectMapper().writeValueAsString(new Response()); when(mockEx.getResponseBodyAsString()).thenReturn(mockRespJson); when(restTemplate.postForEntity(eq(TEST_ENDPOINT), any(HttpEntity.class), eq(Response.class))) .thenThrow(mockEx); targetService.processData(mockRequest, mockHeaders, "high"); verify(targetService, times(1)).func8(); }
注意事项
- 如果你的
someendpoint是通过配置注入的字段,可以在测试类用@TestPropertySource注入测试值,保证打桩时的参数匹配正确 - 如果func1~func8是私有方法,无需验证方法调用,改为验证方法执行后的业务副作用即可,比如是否修改了成员变量、是否调用了其他第三方依赖的方法
- 测试异常分支的兜底逻辑时,必须模拟合法的响应体内容,否则
readValue方法会抛出解析异常,导致测试失败
内容的提问来源于stack exchange,提问作者Ag863
相关产品推荐
相关产品推荐

