使用@RestControllerAdvice与@ExceptionHandler后单元测试预期异常不触发问题
实现方案
1. 异常日志记录
直接在全局异常处理类的@ExceptionHandler方法中手动打印异常日志即可,不会影响原有正常的响应返回逻辑:
@RestControllerAdvice public class GlobalExceptionHandler { private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class); @ExceptionHandler(BusinessException.class) public ResponseEntity<ErrorResponse> handleBusinessException(BusinessException e) { // 最后传入异常对象e即可打印完整堆栈信息,按需调整日志级别和内容 log.error("业务异常触发,错误码:{},错误描述:{}", e.getErrorCode(), e.getMessage(), e); return ResponseEntity.status(HttpStatus.BAD_REQUEST) .body(new ErrorResponse(e.getErrorCode(), e.getMessage())); } }
注意:不要在
@ExceptionHandler方法中重新抛出捕获的异常,否则会导致异常进入Spring MVC默认处理流程,破坏你原有正常的响应返回逻辑
2. 单元测试适配
根据你的测试场景选择对应方案即可:
2.1 Controller层MockMvc测试(走完整请求链路)
不需要断言异常抛出,直接校验接口返回的状态码、响应体内容是否符合对应异常的配置,就能确认异常确实触发:
@SpringBootTest @AutoConfigureMockMvc public class UserControllerTest { @Autowired private MockMvc mockMvc; @Test public void testNonExistUserQuery() throws Exception { mockMvc.perform(get("/user/10000")) // 该ID对应数据不存在,预期抛用户不存在异常 .andExpect(status().isBadRequest()) .andExpect(jsonPath("$.errorCode").value("USER_NOT_FOUND")) .andExpect(jsonPath("$.message").value("用户不存在")); } }
2.2 Service层单元测试(只校验业务逻辑)
测试时不要将@RestControllerAdvice修饰的全局异常处理类加载到测试上下文,即可正常断言异常抛出:
// 仅加载所需的Service相关Bean,不引入web层异常处理组件 @SpringBootTest(classes = {UserService.class}) public class UserServiceTest { @Autowired private UserService userService; @Test public void testNonExistUserQuery() { // 直接断言异常抛出即可 assertThatThrownBy(() -> userService.getById(10000L)) .isInstanceOf(BusinessException.class) .hasMessage("用户不存在"); } }
如果需要批量排除全局异常Handler,可以通过自定义测试配置的扫描过滤规则实现:
@TestConfiguration @ComponentScan(excludeFilters = { @ComponentScan.Filter(type = FilterType.ANNOTATION, value = RestControllerAdvice.class) }) public class TestExcludeGlobalExceptionConfig { }
内容的提问来源于stack exchange,提问作者Vahancho22
相关产品推荐
相关产品推荐

