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
相关产品推荐
相关产品推荐

