Spring MVC测试中的空异常主体

问题描述 投票:9回答:2

我在尝试使MockMvc在响应正文中包含异常消息时遇到麻烦。我有一个控制器,如下所示:

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

BadRequestException看起来像这样:

@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) { /* ... */ }

}

并且我针对/user/new控制器运行以下测试:

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

将显示以下输出:

  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 = []

有人知道为什么Body输出中缺少print()吗?

Edit:我没有使用任何自定义异常处理程序,并且在运行服务器时代码按预期工作。也就是说,运行应用程序并对服务器发出相同的请求将返回

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

如预期。因此,我认为MockMvc存在问题。它以某种方式未捕获到异常的message字段,而常规应用程序服务器的默认异常处理程序按预期工作。

spring spring-mvc exception-handling spring-mvc-test
2个回答
9
投票

打开此问题的ticket之后,有人告诉我,正文中的错误消息由Spring Boot处理,它在Servlet容器级别配置错误映射,并且由于Spring MVC Test使用模拟Servlet请求运行/响应,没有这样的错误映射。此外,他们建议我至少创建一个@WebIntegrationTest并坚持使用Spring MVC Test作为控制器逻辑。

最终,我决定使用自己的自定义异常处理程序,并像以前一样坚持使用MockMvc作为其余部分。

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

}

3
投票

这可能意味着您要么没有处理异常,要么就把尸体留空了。要处理异常,可以在控制器中添加一个错误处理程序

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

或如果您使用的是3.2或更高版本,则使用全局错误处理程序

@ControllerAdvice
public class GlobalExceptionHandler {

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

主体将被填充,您应该用错误消息填充它


0
投票

[在Volkan的答案中添加评论:git issue已更新,对我来说最新答案是可以的。

.andReturn().getResolvedException().getMessage();
© www.soinside.com 2019 - 2024. All rights reserved.