try springboot handling example error custom controlleradvice catch spring spring-mvc exception-handling spring-mvc-test

example - springboot error handling



Cuerpo de excepción vacío en Spring MVC Test (2)

Esto probablemente significa que no manejó la excepción o que realmente dejó el cuerpo vacío. Para manejar la excepción, agregue un controlador de errores en el controlador

@ExceptionHandler public @ResponseBody String handle(BadRequestException e) { return "I''m the body"; }

o usuario, el controlador de error global si tiene 3.2 o superior

@ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler public @ResponseBody String handleBadRequestException(BadRequestException ex) { return "I''m the body"; } }

con esto, el cuerpo se poblará, debes rellenarlo con tu mensaje de error

Estoy teniendo problemas al intentar que MockMvc incluya el mensaje de excepción en el cuerpo de la respuesta. Tengo un controlador de la siguiente manera:

@RequestMapping("/user/new") public AbstractResponse create(@Valid NewUserParameters params, BindingResult bindingResult) { if (bindingResult.hasErrors()) throw BadRequestException.of(bindingResult); // ... }

donde BadRequestException ve así:

@ResponseStatus(value = HttpStatus.BAD_REQUEST, reason = "bad request") public class BadRequestException extends IllegalArgumentException { public BadRequestException(String cause) { super(cause); } public static BadRequestException of(BindingResult bindingResult) { /* ... */ } }

Y ejecuto la siguiente prueba contra /user/new controller:

@Test public void testUserNew() throws Exception { getMockMvc().perform(post("/user/new") .param("username", username) .param("password", password)) .andDo(print()) .andExpect(status().isOk()); }

que imprime el siguiente resultado:

Resolved Exception: Type = controller.exception.BadRequestException ModelAndView: View name = null View = null Model = null FlashMap: MockHttpServletResponse: Status = 400 Error message = bad request Headers = {X-Content-Type-Options=[nosniff], X-XSS-Protection=[1; mode=block], Cache-Control=[no-cache, no-store, max-age=0, must-revalidate], Pragma=[no-cache], Expires=[0], X-Frame-Options=[DENY]} Content type = null Body = Forwarded URL = null Redirected URL = null Cookies = []

¿Alguien tiene una idea de por qué falta Body en la salida print() ?

Editar: no estoy usando ningún manejador de excepción personalizado y el código funciona como se espera cuando ejecuto el servidor. Es decir, ejecutar la aplicación y hacer que la misma solicitud al servidor regrese

{"timestamp":1423076185822, "status":400, "error":"Bad Request", "exception":"controller.exception.BadRequestException", "message":"binding failed for field(s): password, username, username", "path":"/user/new"}

como se esperaba. Por lo tanto, supongo que hay un problema con el MockMvc . De alguna manera no capta el campo de message de la excepción, mientras que el controlador de excepción predeterminado del servidor de aplicaciones normal funciona como se esperaba.


Después de abrir un ticket para el problema, me informaron que el mensaje de error en el cuerpo está a cargo de Spring Boot, que configura las asignaciones de error en el nivel del contenedor de Servlet y, dado que Spring MVC Test se ejecuta con una solicitud / respuesta de Servlet, hay sin tal mapeo de error. Además, me recomendaron crear al menos un @WebIntegrationTest y @WebIntegrationTest a Spring MVC Test para la lógica de mi controlador.

Eventualmente, decidí ir con mi propio manejador de excepciones personalizado y MockMvc a MockMvc para el resto como antes.

@ControllerAdvice public class CustomExceptionHandler { @ExceptionHandler(Throwable.class) public @ResponseBody ExceptionResponse handle(HttpServletResponse response, Throwable throwable) { HttpStatus status = Optional .ofNullable(AnnotationUtils.getAnnotation(throwable.getClass(), ResponseStatus.class)) .map(ResponseStatus::value) .orElse(HttpStatus.INTERNAL_SERVER_ERROR); response.setStatus(status.value()); return new ExceptionResponse(throwable.getMessage()); } } @Data public class ExceptionResponse extends AbstractResponse { private final long timestamp = System.currentTimeMillis(); private final String message; @JsonCreator public ExceptionResponse(String message) { checkNotNull(message, "message == NULL"); this.message = message; } }