MockMvc测试AppUserController时ResourceNotFoundException抛出异常问题排查
核心问题分析
你遇到的NestedServletException是因为Spring MVC的全局异常处理器未正确捕获并处理ResourceNotFoundException,导致异常直接冒泡到MockMvc层面,而非返回预期的404响应。以下是具体排查点和解决办法:
排查点1:全局异常处理器是否被测试上下文加载
如果测试类使用@WebMvcTest(AppUserController.class),该注解默认仅扫描指定控制器类,不会自动加载@ControllerAdvice标记的全局异常处理器。
解决办法:
在测试类上添加@Import(GlobalExceptionHandler.class),手动将异常处理器纳入测试上下文:
@WebMvcTest(AppUserController.class) @Import(GlobalExceptionHandler.class) class AppUserControllerTest { // 测试代码 }
若使用@SpringBootTest,需确保GlobalExceptionHandler所在包在组件扫描范围内(如与主启动类同包或子包)。
排查点2:MockMvc构建模式是否注册了异常处理器
如果手动构建MockMvc(如使用MockMvcBuilders.standaloneSetup),该模式不会自动识别@ControllerAdvice,需手动注册异常处理器:
修正前:
mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
修正后:
mockMvc = MockMvcBuilders.standaloneSetup(controller) .setControllerAdvice(new GlobalExceptionHandler()) // 手动注册异常处理器 .build();
排查点3:全局异常处理器的捕获逻辑是否正确
检查GlobalExceptionHandler是否准确捕获ResourceNotFoundException并返回404:
@ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(ResourceNotFoundException.class) public ResponseEntity<String> handleResourceNotFound(ResourceNotFoundException ex) { return ResponseEntity.status(HttpStatus.NOT_FOUND).body(ex.getMessage()); } }
确保@ExceptionHandler的参数类型是精确的ResourceNotFoundException,避免用父类(如RuntimeException)覆盖导致优先级问题。
排查点4:Mock对象的注入是否正确
确认测试中UserDetailsServiceImpl的mock已正确注入控制器:
- 使用
@MockBean标记UserDetailsServiceImpl,确保控制器调用的是该mock实例:
@WebMvcTest(AppUserController.class) @Import(GlobalExceptionHandler.class) class AppUserControllerTest { @Autowired private MockMvc mockMvc; @MockBean private UserDetailsServiceImpl userDetailsService; @Test void shouldReturn404WhenUserNotFound() throws Exception { // 模拟抛出异常 when(userDetailsService.findAppUserById(anyLong())) .thenThrow(new ResourceNotFoundException("User not found")); // 执行请求并验证响应 mockMvc.perform(get("/api/users/1")) .andExpect(status().isNotFound()) .andExpect(content().string("User not found")); } }
避免手动创建控制器实例并注入mock,确保Spring管理的控制器使用@MockBean提供的对象。
验证步骤
- 先单独验证全局异常处理器功能:启动应用后手动调用接口,确认是否返回404,排除异常处理器本身的问题。
- 检查测试类上下文配置,确保所有依赖bean都被正确加载。
- 调试测试,确认
userDetailsService.findAppUserById确实抛出了ResourceNotFoundException,且控制器没有额外的try-catch吞掉异常。
内容的提问来源于stack exchange,提问作者Demir

