无法正确测试 ErrorController Spring 引导

Cannot properly test ErrorController Spring Boot

由于本教程 - https://www.baeldung.com/spring-boot-custom-error-page 我想自定义我的错误页面,即。当有人去 www.myweb.com/blablablalb3 我想 return 带有文本 "wrong url request" 的页面时。 一切正常:

@Controller
public class ApiServerErrorController implements ErrorController {

    @Override
    public String getErrorPath() {
        return "error";
    }

    @RequestMapping("/error")
    public String handleError() {
        return "forward:/error-page.html";
    }
}

但是我不知道怎么测试:

@Test
    public void makeRandomRequest__shouldReturnErrorPage() throws Exception {
        this.mockMvc.perform(get(RANDOM_URL))
                .andDo(print());

    }

打印() returns:

MockHttpServletResponse:
           Status = 404
    Error message = null
          Headers = {X-Application-Context=[application:integration:-1]}
     Content type = null
             Body = 
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

所以我不能创建这样的东西:

.andExpect(forwardedUrl("error-page"));

因为它失败了,但是在手动测试中错误页面是 returned。

不幸的是,不支持使用 MockMvc 测试自定义 ErrorController

详细解释见Spring Boot team(source)的官方推荐。

To be sure that any error handling is working fully, it's necessary to involve the servlet container in that testing as it's responsible for error page registration etc. Even if MockMvc itself or a Boot enhancement to MockMvc allowed forwarding to an error page, you'd be testing the testing infrastructure not the real-world scenario that you're actually interested in.

Our recommendation for tests that want to be sure that error handling is working correctly, is to use an embedded container and test with WebTestClient, RestAssured, or TestRestTemplate.

我的建议是使用@ControllerAdvice

通过这种方式,您可以解决该问题,并且可以继续使用 MockMvc,其最大优势是您不需要 运行 服务器。

当然,要显式测试错误页面管理,您需要 运行 服务器。我的建议主要是针对那些已经实现了ErrorController但仍然想使用MockMvc进行单元测试的人。

@ControllerAdvice
public class MyControllerAdvice {

  @ExceptionHandler(FileSizeLimitExceededException.class)
  public ResponseEntity<Throwable> handleFileException(HttpServletRequest request, FileSizeLimitExceededException ex) {
    return new ResponseEntity<>(ex, HttpStatus.PAYLOAD_TOO_LARGE);
  }

  @ExceptionHandler(Throwable.class)
  public ResponseEntity<Throwable> handleUnexpected(HttpServletRequest request, Throwable throwable) {
    return new ResponseEntity<>(throwable, HttpStatus.INTERNAL_SERVER_ERROR);
  }

}