使用 RestTemplate 测试 ExceptionHandler
Posted
技术标签:
【中文标题】使用 RestTemplate 测试 ExceptionHandler【英文标题】:Test ExceptionHandler with RestTemplate 【发布时间】:2022-01-22 01:59:21 【问题描述】:我有一个对外部 API 产生影响的方法,并且我编写了异常处理程序来处理错误并在发生错误时发送对客户端友好的响应。我需要测试来自该外部 API 的非 200 OK 响应,例如错误请求、内部服务器错误,并断言应该调用异常处理程序方法以发送对客户端友好的消息。我能够成功地将外部 API 的响应模拟为错误请求,但它没有抛出 HttpStatusCodeException 理想情况下抛出 4xx 状态代码以及如何验证异常处理程序的方法调用
private final RestTemplate restTemplate = Mockito.mock(RestTemplate.class);
private final HttpHeaders httpHeaders = new HttpHeaders();
private final NotificationServiceImpl notificationService = new NotificationServiceImpl(restTemplate, httpHeaders, NOTIFICATION_API_URL, PRIMARY_NOTIFIERS, CC_NOTIFIERS, LANG, APPLICATION_NAME);
@Autowired
private ExceptionTranslator exceptionTranslator;
@Test
void testErrorOnSendNotification()
Map<String, Instant> messages = Map.of("sample message", Instant.now());
ResponseEntity<HttpStatusCodeException> responseEntity =
new ResponseEntity<>(HttpStatus.BAD_REQUEST);
when(restTemplate.exchange(
ArgumentMatchers.anyString(),
ArgumentMatchers.any(HttpMethod.class),
ArgumentMatchers.any(),
ArgumentMatchers.<Class<HttpStatusCodeException>>any()))
.thenReturn(responseEntity);
// assertThrows(HttpStatusCodeException.class, () -> notificationService.sendNotification(messages));
verify(exceptionTranslator, times(1)).handleExceptions(any(), any());
@ExceptionHandler(Exception.class)
public ResponseEntity<Problem> handleExceptions(NativeWebRequest request, Exception error)
Problem problem =
Problem.builder()
.withStatus(Status.BAD_REQUEST)
.withTitle(error.getMessage())
.withDetail(ExceptionUtils.getRootCauseMessage(error))
.build();
return create(error, problem, request);
【问题讨论】:
【参考方案1】:您在嘲笑 restTemplate
响应。实际的@ExceptionHandler
根本没有被调用。您正在绕过该层。
在您的情况下,为了验证ExceptionHandler
,可以模拟您的service
层,但必须继续执行实际的REST 调用,并且必须触发真正的response
,以便为您服务验证响应Status Code
+ message
。
下面的伪代码:
@Service
class Service
public void doSomeBusinessLogic() throws SomeException;
@RestController
class ControllerUsingService
@AutoWired
private Service service;
@POST
public Response somePostMethidUsingService() throws SomeException
service.doSomeBusinessLogic(someString);
@Test
void testErrorOnSendNotification()
when(service.doSomeBusinessLogic(anyString()))
.thenThrow(SomeExceptionException.class);
Response receivedResponse = restTemplate.post(request, headers, etc);
//assert receivedResponse status code + message.
希望这是有道理的,
进一步说明:
通过做:
ResponseEntity<HttpStatusCodeException> responseEntity =
new ResponseEntity<>(HttpStatus.BAD_REQUEST);
when(restTemplate.exchange(
ArgumentMatchers.anyString(),
ArgumentMatchers.any(HttpMethod.class),
ArgumentMatchers.any(),
ArgumentMatchers.<Class<HttpStatusCodeException>>any()))
.thenReturn(responseEntity);
你绕过了服务层,实际上是说每当我向/API/xyz
发出请求时,我应该会收到BAD_REQUEST
。这意味着您拥有的任何异常处理都将被绕过。
【讨论】:
以上是关于使用 RestTemplate 测试 ExceptionHandler的主要内容,如果未能解决你的问题,请参考以下文章
使用注入 java 和 spring boot 的 RestTemplate 类进行单元测试
使用 RestTemplate 测试 ExceptionHandler