
mockmvc 单元测试中,controller 抛出的自定义异常(如 resourcenotfoundexception)未被 @controlleradvice 拦截,导致测试失败并抛出 nestedservletexception;根本原因是 standalonesetup 未注册异常处理器。
mockmvc 单元测试中,controller 抛出的自定义异常(如 resourcenotfoundexception)未被 @controlleradvice 拦截,导致测试失败并抛出 nestedservletexception;根本原因是 standalonesetup 未注册异常处理器。
在使用 @WebMvcTest 注解进行控制器层测试时,若同时采用 MockMvcBuilders.standaloneSetup(...) 手动构建 MockMvc 实例,Spring 将跳过自动扫描和注册 @ControllerAdvice 组件(如全局异常处理器)的过程。这正是本例中 AppExceptionHandler 未被调用、ResourceNotFoundException 未经处理直接向上冒泡、最终触发 NestedServletException 的根本原因。
虽然 @WebMvcTest 默认会加载 @ControllerAdvice,但一旦你在 @BeforeEach 中显式调用 standaloneSetup(underTest).build(),就覆盖了 Spring Boot Test 自动配置的完整 MVC 环境(含拦截器、异常处理器、消息转换器等),退化为“纯手动”模式 —— 此时必须显式注入所有依赖组件。
✅ 正确做法:在 standaloneSetup 中通过 .setControllerAdvice(...) 显式注册异常处理器:
@BeforeEach
void setUp() {
mockMvc = MockMvcBuilders.standaloneSetup(underTest)
.setControllerAdvice(new AppExceptionHandler()) // ✅ 关键修复:注册异常处理器
.build();
}
⚠️ 注意事项:
- new AppExceptionHandler() 是无参构造,确保其内部逻辑不依赖 Spring Bean(如 @Autowired 字段)。若需注入服务(例如日志记录器或审计服务),应改用 @MockBean 或 @Autowired 注入后传入构造器。
- 若 AppExceptionHandler 本身依赖其他 Spring Bean(如 MessageSource),推荐改用 @WebMvcTest 的默认上下文启动方式(即移除 standaloneSetup),并通过 @Import 显式引入必要配置类,或使用 @AutoConfigureTestDatabase 等组合注解保持环境一致性。
- @WebMvcTest(useDefaultFilters = false) 已禁用默认组件扫描,因此 @ControllerAdvice 类不会被自动发现 —— 这进一步强化了手动注册的必要性。
? 补充建议:优化测试断言逻辑
当前测试尝试反序列化响应体为 ResourceNotFoundException,但该类是服务端异常载体,并非标准 REST 响应 DTO。更健壮的做法是验证响应状态码与 JSON 错误结构是否符合预期(如包含 message、httpStatusCode 字段):
@Test
void findAppUserById_throwsNotFound() throws Exception {
UUID uuid = UUID.fromString("ac0a1859-8e59-4ede-8def-043c32aa3208");
when(userDetailsService.findAppUserById(any())).thenThrow(new ResourceNotFoundException("Kullanıcı bulunamadı"));
mockMvc.perform(get("/app-users/" + uuid))
.andExpect(status().isNotFound())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$.message").value("Kullanıcı bulunamadı"))
.andExpect(jsonPath("$.httpStatusCode").value(404));
}
✅ 总结:standaloneSetup 是轻量级测试手段,但需“手动补全” MVC 全链路能力;全局异常处理绝非开箱即用,必须显式注册 @ControllerAdvice。坚持这一原则,可避免 90% 的 MockMvc 异常测试失效问题。











