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

MockMvc无法捕获AccessDeniedException,测试失败求助

MockMvc无法捕获AccessDeniedException的解决方案

问题场景

我编写了如下POST请求测试代码:

assertThrows("Access Denied for non Blappity Roles",
             () -> mvc.perform(post(url)
                        .content(requestStr)
                        .accept(ContentType.APPLICATION_JSON.toString())
                        .with(csrf())
                        .contentType(MediaType.APPLICATION_JSON))
                   .andExpect(__ -> assertThat(__.getResolvedException(), CoreMatchers.instanceOf(AccessDeniedException.class))),
             Matchers.instanceOf(AccessDeniedException.class))

同时定义了如下异常处理器:

@ExceptionHandler(AccessDeniedException.class)
public void accessDeniedException(HttpServletRequest request, HttpServletResponse response, Exception e) throws Exception {
    e.printStackTrace(System.err);
    log.error("Access Denied Exception {}", e.getClass(), e);
    throw e;
}

测试始终失败,MockMvc的perform方法无法捕获AccessDeniedException,异常绕过匹配器导致测试失败,猜测异常被某个过滤器拦截,想请教如何让MockMvc捕获该异常?

解决方案

1. 调整异常处理器的行为

你的异常处理器最后重新抛出了AccessDeniedException,但在Spring MVC流程中,这类异常会被框架过滤器(比如Spring Security的ExceptionTranslationFilter)拦截,转换成HTTP 403响应,不会被MockMvc的getResolvedException()捕获。

修改异常处理器,直接设置响应状态而非重新抛出:

@ExceptionHandler(AccessDeniedException.class)
public void accessDeniedException(HttpServletRequest request, HttpServletResponse response, Exception e) throws IOException {
    e.printStackTrace(System.err);
    log.error("Access Denied Exception {}", e.getClass(), e);
    response.sendError(HttpServletResponse.SC_FORBIDDEN, "Access Denied");
}

2. 调整测试断言逻辑

如果保留原异常处理器的抛异常行为,异常会被过滤器处理为403响应,此时应断言响应状态而非捕获异常:

mvc.perform(post(url)
        .content(requestStr)
        .accept(ContentType.APPLICATION_JSON.toString())
        .with(csrf())
        .contentType(MediaType.APPLICATION_JSON))
    .andExpect(status().isForbidden());

3. 确保MockMvc包含完整过滤器链

若项目使用Spring Security,需通过springSecurity()配置MockMvc,让过滤器链纳入测试流程:

@Autowired
private WebApplicationContext context;

private MockMvc mvc;

@BeforeEach
void setUp() {
    mvc = MockMvcBuilders.webAppContextSetup(context)
            .apply(springSecurity())
            .build();
}

4. 临时跳过过滤器(仅调试用)

若需强制MockMvc直接捕获异常,可构建MockMvc时替换过滤器,但此方法会偏离真实运行环境,不推荐正式测试使用:

mvc = MockMvcBuilders.webAppContextSetup(context)
        .addFilters((request, response, chain) -> chain.doFilter(request, response))
        .build();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 14:43:17