简体   繁体   中英

Test ExceptionHandler with RestTemplate

I have a method that makes a hit to external API and I have the exception handler is written to handle the errors and send the client-friendly response in case of errors. I have a requirement to test the non 200 OK responses from that external API such as Bad Request, Internal Server Error, and assert that the exception handler method should be invoked to send a client-friendly message. I am able to successfully mock the response of external API as Bad Request but it is not throwing the HttpStatusCodeException which is ideally thrown for 4xx status code and how can I verify method invocation of exception handler

  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);
  }

You are mocking the restTemplate response. The actual @ExceptionHandler is not called at all. You are bypassing that layer.

In your case, in order to verify the ExceptionHandler , your service layer can be mocked, but the actual REST call has to proceed through, and a REAL response has to be triggered, in order for you to verify the Response Status Code + message .

Psuedo Code below:

@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.
  }

Hope that makes sense,

For further clarification:

By doing:

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);

You are bypassing service layer and actually stating that whenever I make a request towards /API/xyz , then I should receive a BAD_REQUEST . That means whatever exception handling you have is going to be bypassed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM