如何使用junit在spring-boot中测试常见错误ErrorController

时间:2017-03-13 10:22:39

标签: spring-mvc spring-boot junit

在spring boot项目中,我想用Junit测试我的ErrorController。 代码如下面的代码段所示。

@RestController
public class ApiErrorController implements ErrorController {
  private static final Logger LOGGER = LoggerFactory.getLogger(ApiErrorController.class);

  @Value("${server.error.path}")
  private String errorPath;

  @Override
  public String getErrorPath() {
    return this.errorPath;
  }

  @RequestMapping("/error")
  public ResponseEntity<ErrorResult> error(HttpServletRequest request, HttpServletResponse response) {

    String requestURI = (String) request.getAttribute("javax.servlet.forward.request_uri");
    LOGGER.info("error handling start url = {}", requestURI);

    String servletMessage = (String) request.getAttribute("javax.servlet.error.message");
    Integer servletStatus = (Integer) request.getAttribute("javax.servlet.error.status_code");

    String[] messages = new String[0];
    if (!StringUtils.isNullOrEmpty(servletMessage)) {
      messages = new String[] { servletMessage };
    }
    HttpStatus status = HttpStatus.INTERNAL_SERVER_ERROR;
    try {
      if (servletStatus != null && servletStatus instanceof Integer) {
        status = HttpStatus.valueOf(servletStatus);
      }
    } catch (Exception ex) { // test this exception
      LOGGER.warn("http status not converted.{}", request.getAttribute("javax.servlet.error.status_code"), ex);
    }
    ErrorResult body = new ErrorResult();
    body.setMessages(messages);
    ResponseEntity<ErrorResult> responseResult = new ResponseEntity<>(body, status);
    return responseResult;
  }
}

当我的Controller中发生业务异常时(例如AbcController),程序进入ExceptionControllerAdvice类。 如果ExceptionControllerAdvice中发生异常,则程序进入上述ApiErrorController类。

有人能告诉我如何测试HttpStatus.valueOf(servletStatus)失败的情况吗? 另外,我希望request.getAttribute("javax.servlet.error.message")返回一个非空字符串。 如何实现我想测试的内容?

顺便说一句,我不想只测试error方法的逻辑。我想用我提到的AbcController进行测试。我想要的是当AbcController中发生错误时,error中的ApiErrorController方法可以成功处理它。

APPEND : 例如,ExceptionControllerAdvice将处理业务异常。

@ControllerAdvice(annotations = RestController.class)
public class ExceptionControllerAdvice {
  private static final Logger LOGGER = LoggerFactory.getLogger(ExceptionControllerAdvice.class);

  @ExceptionHandler({ BusinessCloudException.class })
  public ResponseEntity<ErrorResult> handleBlCloudException(HttpServletRequest request, HttpServletResponse response,
                                                            BlCloudException ex) {

    HttpStatus status = ErrorUtils.toHttpStatus(ex.getType());
    ErrorResult body = new ErrorResult();
    body.setMessages(ex.getMessageArray());
    ResponseEntity<ErrorResult> responseResult = new ResponseEntity<>(body, status);
    return responseResult;
  }
}

如果handleBlCloudException方法中发生错误,则程序会进入ApiErrorController以处理此错误。

该程序如何生成特定的servletStatusjavax.servlet.error.message?如何嘲笑这样做?

1 个答案:

答案 0 :(得分:0)

首先,该错误方法有很多事情要做。您可以考虑将一些逻辑移动到专门的类/公共方法。

除此之外,我建议使用Mockito。

Fist of all创建一个封装HttpStatus检索的方法:

HttpStatus getHttpStatusByServletStatus(Integer servletStatus){
    return HttpStatus.valueOf(servletStatus);
}

并将您的代码更改为:

  if (servletStatus != null && servletStatus instanceof Integer) {
    status = getHttpStatusByServletStatus(servletStatus);
  }

然后是测试类:

public ApiErrorControllerTest {

 @Spy
 private ApiErrorController apiErrorController; 

 @Mock
 HttpServletRequest requestMock;
 @Mock
 HttpServletResponse responseMock;

 @Befire
 public void init(){
    MockitoAnnotations.initMocks(this);
 }

 @Test
 public void test(){
    // Arrange

   HttpStatus expectedStatus = // expected status
   String expectedErrorMessage = // ..

   doReturn(expectedStatus).when(apiErrorController)
     .getHttpStatusByServletStatus(Mockito.anyString());

   when(requestMock.getAttribute("javax.servlet.error.message"))
     .thenReturn(expectedErrorMessage);

   // other setup.. 

   // Act
   apiErrorController.error(requestMock, responseMock);

   // Assertions
 }