SpringBoot Controller层测试抛出JSONException:无法解析JSON字符串
问题原因排查及解决方案
1. MockMvc初始化未关联全局异常处理器
如果你的@BeforeEach里用standaloneSetup手动构建MockMvc,但没注册@ControllerAdvice类,MockMvc无法识别全局异常处理器,返回的可能是默认错误页面(HTML)而非自定义JSON响应,自然会触发JSON解析失败。
- 错误写法:
@BeforeEach void setUp() { mockMvc = MockMvcBuilders.standaloneSetup(userController).build(); } - 修复方式:
要么用webAppContextSetup加载完整Spring上下文,自动扫描@ControllerAdvice:
要么手动给@Autowired private WebApplicationContext webCtx; @BeforeEach void setUp() { mockMvc = MockMvcBuilders.webAppContextSetup(webCtx).build(); }standaloneSetup添加全局异常处理器:@BeforeEach void setUp() { mockMvc = MockMvcBuilders.standaloneSetup(userController) .setControllerAdvice(new GlobalExceptionHandler()) .build(); }
2. ExceptionHandler返回的不是合法JSON
如果你的异常处理器直接返回字符串而非JSON结构,比如:
@ExceptionHandler(IllegalArgumentException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) public String handleError() { return "参数非法"; }
服务器会返回纯文本,MockMvc尝试解析成JSON时必然报错。
- 修正:返回带
@ResponseBody的POJO或ResponseEntity:
@ExceptionHandler(IllegalArgumentException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) @ResponseBody public ErrorResult handleError() { return new ErrorResult("参数非法"); }
3. MockMvc缺少自定义ObjectMapper配置
如果项目里自定义了ObjectMapper(比如配置日期格式、空值过滤),但手动初始化MockMvc时没指定该转换器,默认ObjectMapper可能无法正确序列化异常响应对象,生成无效JSON。
- 修复:注入自定义ObjectMapper并配置到MockMvc:
@Autowired private ObjectMapper customObjectMapper; @BeforeEach void setUp() { mockMvc = MockMvcBuilders.standaloneSetup(userController) .setMessageConverters(new MappingJackson2HttpMessageConverter(customObjectMapper)) .build(); }
4. 测试请求未指定Accept头
如果测试时没加Accept: application/json,服务器可能返回text/html格式的默认错误页,而非JSON响应,导致解析失败。
- 修复:在请求中添加Accept头:
mockMvc.perform(get("/users/{id}", -1) .accept(MediaType.APPLICATION_JSON)) .andExpect(status().isBadRequest()) .andExpect(jsonPath("$.msg").value("无效ID"));
5. 模拟的异常类型不匹配ExceptionHandler
如果Mockito模拟Service抛出的异常,不在你的ExceptionHandler处理范围内,Spring MVC会返回默认的错误页面(HTML),而非自定义JSON响应,自然无法解析成JSON。
- 检查测试代码:确保模拟抛出的异常是ExceptionHandler声明处理的类型,比如:
// 确保这里抛出的IllegalArgumentException是处理器能处理的 when(userService.findById(-1)).thenThrow(new IllegalArgumentException("无效ID"));
内容的提问来源于stack exchange,提问作者Donghwan Lee
相关产品推荐
相关产品推荐

