java - 使用自定义异常处理测试 REST 端点

标签 java testing spring-boot exception mockmvc

我正在使用 Spring 微服务(模块)开发一个项目,我想使用 MockMvc 测试我的 REST 端点。我的测试在请求有效但在请求无效 url 时不起作用的情况下工作正常。不工作是指我的自定义异常处理程序 (@ControllerAdvice) 没有被调用,异常被抛出并且测试失败。

我的异常处理程序和测试类在不同的模块中实现。

通用模块(ExceptionHandler)

@ControllerAdvice
public class CoreExceptionHandler {

    @ExceptionHandler(value = Exception.class)
    public ResponseEntity<ErrorMessageDTO> handleException(Exception ex, HttpServletRequest request) {

        // Getting servlet request URL
        String uri = request.getRequestURI();
        HttpStatus a;

        ErrorMessageDTO errorMessage;

        if (ex instanceof CoreException) {
            CoreException e = (CoreException) ex;
            ...
            errorMessage = new ErrorMessageDTO(e, uri);
        } else {
            errorMessage = new ErrorMessageDTO(ex, uri);
            ...
        }
        return new ResponseEntity<ErrorMessageDTO>(errorMessage, a);
    }
}

国家模块

这是实现我的 REST 端点和测试类的地方。公共(public)模块依赖包含在该模块的pom.xml中,并通过主类扫描包。

CountryApplication.java

@EnableCaching
@EnableDiscoveryClient
@EnableAspectJAutoProxy
@SpringBootApplication(scanBasePackages = {
    "com.something1.something2.something3.common.exception",
    "com.something1.something2.something3.common.util.logged",
    "com.something1.something2.something3.country"
})
public class CountryApplication {
    public static void main(String[] args) throws Exception {
        SpringApplication.run(CountryApplication.class, args);
    }
    ...
}

国家服务.java

这是我的服务类中的一个方法。

@GetMapping("/{id:\\d+}")
public CountryDTO getCountryById(@PathVariable("id") Integer id) throws CoreException {

    Country countryEntity = this.countryRepository.findOne(id);

    // requesting for id that does not exist
    if (countryEntity == null) {
        throw new CoreException(CoreError.ENTITY_NOT_FOUND);
    }
    return this.countryMapper.daoToDto(countryEntity);
}

CountryServiceTest.java

@SpringBootTest
@AutoConfigureMockMvc
@AutoConfigureTestDatabase
@RunWith(SpringRunner.class)
public class CountryServiceTest {
    ...
    @Autowired
    private MockMvc mockMvc;

    @Test
    public void getByIdTest() throws Exception {

        // Get by id exists
        mockMvc.perform(get("/2"))
            .andExpect(status().isOk())
            .andExpect(content().contentType(contentType))
            .andDo(print());

        // Get by id not exists. NOT WORKING
          mockMvc.perform(get("/100000"))
            .andExpect(status().isNotFound())
            .andExpect(content().contentType(contentType));

    }
}

正如我上面所描述的,问题是在测试方法的第二个请求中,CoreExceptionHandler 没有被调用并且测试失败抛出:

NestedServletException:请求处理失败;嵌套异常是 com.something1.something2.something3.common.exception.CoreException

公共(public)模块的依赖性配置良好(至少当我在非测试模式下部署时),因为我也将它用于其他事情,而且当我不测试时会调用 ExceptionHandler。

另一件奇怪的事情是,当我部署我的测试时,Spring Boot 的日志显示检测到 CoreExceptionHandler。这是线。 在 coreExceptionHandler 中检测到 @ExceptionHandler 方法

最佳答案

有两个问题解释如下:

(1) ControllerAdvice 没有为 CountryServiceTest 类中的 MockMvc 对象设置,可以如下所示完成:

MockMvc mockMvc = standaloneSetup(yourController)
        .setHandlerExceptionResolvers(new CoreExceptionHandler())
        .build();

(2) 因为 CoreException 是 Spring 容器对 NestedServletException 的包装,所以需要使用 exception.getCause() 来检查您的异常,如下所示:

@ControllerAdvice
    public class CoreExceptionHandler {

        @ExceptionHandler(value = Exception.class)
        public ResponseEntity<ErrorMessageDTO> handleException(Exception ex, 
            HttpServletRequest request) {

            // Getting servlet request URL
            String uri = request.getRequestURI();
            HttpStatus a;

            ErrorMessageDTO errorMessage;

            //check with exception cause
            if (ex.getCause() instanceof CoreException) {
                CoreException e = (CoreException) ex;
                ...
                errorMessage = new ErrorMessageDTO(e, uri);
            } else if (ex instanceof CoreException) {
               //this block will be used only when direct CoreException triggered
                CoreException e = (CoreException) ex;
                ...
                errorMessage = new ErrorMessageDTO(e, uri);
            } else {
                errorMessage = new ErrorMessageDTO(ex, uri);
                ...
            }
            return new ResponseEntity<ErrorMessageDTO>(errorMessage, a);
        }
    }

此外,我建议不要在一个泛型方法中处理所有异常类型,这将很难支持/维护,而是使用多个 @ExceptionHandler 拆分您的 CoreExceptionHandler 方法/类。

关于java - 使用自定义异常处理测试 REST 端点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40626785/

相关文章:

java - 从java程序执行docker命令时出现错误

c# - .NET 无需自动化即可从标签中读取文本

mysql - 尽管检查的行数相似,为什么查询时间会激增?

javascript - 如何设置 mocha 以在 Gatsby 存储库中运行测试

spring-boot - JHipster 微服务 CORS

java - 无法在 Spring-boot 中使用自签名 https 验证来自 Postman 的 POST/GET 请求方法

java - 如何知道数组是否包含给定的值

java - 如何在java中递归地在链表前面添加一个节点

java - 资源处理实践

java - 使用 Apache Camel 和 spring-ws 组件调用基于 SOAP 的服务