You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Mock MVC控制器通知异常处理测试失败问题咨询

排查Controller Advice未处理SecurityException的问题

我来帮你梳理下可能的问题点,这种情况我之前踩过好几次坑,大概率是以下某个细节没处理到位:


1. 先确认SecurityException的全类名是否完全匹配

这是最容易踩的坑!Java里有两个常见的SecurityException:

  • java.lang.SecurityException(JDK自带的基础异常类)
  • org.springframework.security.core.SecurityException(Spring Security的核心异常类)

你要仔细核对:

  • 控制器方法里抛出的实际异常类型,和@ExceptionHandler(SecurityException.class)里指定的是不是同一个类?
  • 比如如果你的代码抛出的是Spring Security的AuthenticationException(它是org.springframework.security.core.SecurityException的子类),理论上@ExceptionHandler(SecurityException.class)能覆盖子类,但前提是你指定的全类名和抛出的异常父类完全一致。

2. 检查异常抛出的时机是否在Controller处理流程内

Spring的@ControllerAdvice只能处理DispatcherServlet接管后的异常,也就是控制器方法内部、参数绑定、消息转换阶段抛出的异常。如果异常是在过滤器层面抛出的(比如Spring Security的Filter拦截请求时抛出的权限异常),那Controller Advice根本管不到——因为过滤器在DispatcherServlet之前执行,这时候的异常会被过滤器自身的异常处理机制处理,比如Spring Security的AuthenticationEntryPoint或者AccessDeniedHandler。

举个例子:如果你的接口加了@PreAuthorize注解,Spring Security的AOP代理在调用控制器方法前就抛出了AccessDeniedException,这时候这个异常不会走到Controller Advice,而是需要你配置Spring Security专属的异常处理器。

3. 验证MockMvc的构建方式是否合适

你用了standaloneSetup模式,这种模式是轻量级的,只初始化指定的控制器和Controller Advice,但如果你的控制器用到了AOP代理(比如Spring Security的注解、自定义AOP),standalone模式可能不会正确生成代理对象,导致异常抛出的逻辑和实际运行时不一致。

建议试试切换到webAppContextSetup模式,加载完整的Spring上下文来构建MockMvc,这样能保证所有Bean、AOP代理都正确初始化:

@Autowired
private WebApplicationContext webApplicationContext;

private MockMvc mockMvc;

@BeforeEach
void setUp() {
    mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
            // 如果用到Spring Security,记得加上这个配置
            .apply(springSecurity())
            .build();
}

4. 确认Controller Advice的注解配置正确

虽然控制台已经打印了检测到@ExceptionHandler方法,但还是再确认下你的ExceptionHandlingControllerAdvice类上有没有加@RestControllerAdvice(返回JSON响应)或者@ControllerAdvice(返回视图)注解?如果只加了@Component,虽然可能被Spring扫描到,但不会被识别为Controller Advice(不过控制台既然检测到了,大概率是加了,但还是确认下更稳妥)。

5. 检查测试方法的写法是否正确

当MockMvc调用被Controller Advice处理的接口时,不会抛出异常,而是会返回处理后的HTTP响应。如果你的测试方法直接让异常传播出来,说明Controller Advice根本没触发。正确的测试写法应该验证响应状态码或响应体,比如:

@Test
void testSecurityExceptionHandling() throws Exception {
    mockMvc.perform(get("/your-secure-endpoint"))
            .andExpect(status().isForbidden()) // 或者你自定义的状态码
            .andExpect(content().json("{\"code\":403,\"message\":\"权限不足\"}")); // 验证自定义响应体
}

先从全类名匹配和异常抛出时机这两个点排查,这是最常见的原因,如果还是解决不了,可以再检查MockMvc的构建模式和测试写法。

内容的提问来源于stack exchange,提问作者FMC

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:00:04