【问题标题】:How cover a ControllerAdvice dedicated to handle exception如何覆盖专用于处理异常的 ControllerAdvice
【发布时间】:2020-09-22 07:23:22
【问题描述】:

我在测试我的 HandleException 时遇到了问题,尽管我已经搜索过,但我只找到了集成错误管理的标准控制器的解决方案,但我单独拥有它。

问题在于,在进行单元测试及其覆盖范围时,我不知道如何正确覆盖它。

@Order(Ordered.HIGHEST_PRECEDENCE)
@ControllerAdvice
public class RestExceptionHandler {

    @ExceptionHandler(AmazonClientException.class)
    protected ResponseEntity<Object> handleAmazonClientException(AmazonClientException ex) {
        return buildResponseEntity(new ApiError(HttpStatus.INTERNAL_SERVER_ERROR, ex));
    }

    @ExceptionHandler(AmazonS3Exception.class)
    protected ResponseEntity<Object> handleAmazonS3Exception(AmazonS3Exception ex) {
        return buildResponseEntity(new ApiError(HttpStatus.NOT_FOUND, ex));

    }

    private ResponseEntity<Object> buildResponseEntity(ApiError apiError) {
        return new ResponseEntity<>(apiError, apiError.getStatus());
    }

}

RestExceptionHandler.class

ApiError.class

@Data
public class ApiError {

    private HttpStatus status;
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy hh:mm:ss")
    private LocalDateTime timestamp;
    private String message;
    private String debugMessage;

    private ApiError() {
        setTimestamp(LocalDateTime.now());
    }

    ApiError(HttpStatus status) {
        this();
        setStatus(status);
    }

    ApiError(HttpStatus status, Throwable ex) {
        this();
        setStatus(status);
        setMessage("Unexpected error");
        setDebugMessage(ex.getLocalizedMessage());
    }

    ApiError(HttpStatus status, String message, Throwable ex) {
        this();
        setStatus(status);
        setMessage(message);
        setDebugMessage(ex.getLocalizedMessage());
    }
 }



怎么看,我只使用我的 RestExceptionHandler ,不调用另一个业务类。

任何建议表示赞赏。

【问题讨论】:

    标签: java spring exception junit


    【解决方案1】:

    要对 @ControllerAdvice 带注释的类进行单元测试,您可以使用 Spring 提供的名为 MockMvc 的东西。 这是对控制器和后续控制器建议进行单元测试的一种非常优雅的方式。

    所以,假设这是我的控制器

    @RestController
    @RequestMapping("api")
    public class RobotController {
    
        private RobotService robotService;
    
        @GetMapping
        public Collection<Integer> get() {
            throw new DemoException();
        }
    }
    

    这是我的控制器建议; DemoException 只是一个扩展 RuntimeException 的空类。

    @RestControllerAdvice
    public class RestExceptionHandler {
        @ExceptionHandler(DemoException.class)
        public ResponseEntity<Object> handleException(DemoException dex) {
            return ResponseEntity
                    .status(400)
                    .body("Bad request");
        }
    }
    

    所以,这意味着,向BASEURL/api 发送一个GET 请求会给我Bad request 带有400 状态码的文本响应。

    好的,既然我们已经完成了设置,让我们开始实际的单元测试。这是一个非常简单的单元测试,但它可以满足您的需求。

    public class AdviceTest {
    
        private final MockMvc mockMvc = MockMvcBuilders
                .standaloneSetup(new RobotController())
                .setControllerAdvice(new RestExceptionHandler())
                .build();
    
        @Test
        void testGetFails() {
            mockMvc.perform(
                        MockMvcRequestBuilders.get("/api")
                    ).andExpect(
                           status().isBadRequest()
                    );
        }
    }
    

    那么,让我解释一下MockMvc 对象的初始化。有两个版本。

    1. 独立设置,您只需提供手动创建的控制器对象。

    2. Web 应用程序上下文,您只需在其中提供自动装配的应用程序上下文。

    您还可以自动连接 MockMvc 对象。

    在这两个中,我非常喜欢前者,因为它不包括整个 Spring 上下文,因此速度更快。

    有很多方法可以从检查 json 内容到路径。你可以在这里阅读更多:

    Spring Guide

    Baeldung

    【讨论】:

    • 哦,太简单了,谢谢,总是看到有手柄和RestApi控制器建议的人。感谢您的帮助。
    猜你喜欢
    • 2016-11-22
    • 2017-01-23
    • 2018-07-13
    • 2022-10-14
    • 2014-08-26
    • 1970-01-01
    • 2015-12-15
    • 1970-01-01
    相关资源
    最近更新 更多