Spring Boot Rest Controller PATCH测试报错:预期200实际返回400
看起来你在测试SalesOrderController的PATCH接口时遇到了400 Bad Request的断言失败,这大概率是请求参数校验环节出了问题,我来帮你一步步排查和解决:
核心原因分析
你的控制器方法reassignSalesOrder对@RequestBody参数添加了@Valid注解,这会触发Spring的Bean Validation(JSR-380)校验逻辑。但在测试类的setUp方法里,你只是用最简单的方式构建了MockMvc:
mockMvc = MockMvcBuilders.standaloneSetup(salesOrderController).build();
这种独立设置的MockMvc默认不会加载Spring的校验器,导致校验逻辑触发后没有合适的处理器,直接返回400错误,根本没走到你的业务代码里,自然和你期望的200状态码不匹配。
解决步骤
1. 给MockMvc配置校验器
修改测试类的setUp方法,添加校验器的初始化和配置,这样MockMvc就能正确处理@Valid的校验逻辑了:
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; // ... private LocalValidatorFactoryBean validator; @Before public void setUp() throws Exception { // 初始化校验器 validator = new LocalValidatorFactoryBean(); validator.afterPropertiesSet(); // 给MockMvc配置校验器 mockMvc = MockMvcBuilders.standaloneSetup(salesOrderController) .setValidator(validator) .build(); }
2. 排查请求参数是否符合校验规则
如果配置校验器后还是返回400,那就要检查ReassignSalesOrderRequest类中的校验注解是否被你的测试数据满足。比如:
- 假设
redirectOption有@NotBlank注解,你测试中设置的"Satellite"是合法的,但如果有@Pattern限制了特定枚举值,要确认是否匹配; - 如果
salesOrderIds有@NotEmpty注解,你用Collections.singletonList(1L)是没问题的; - 如果
satelliteId在redirectOption为"Satellite"时是必填项(比如用@NotNull配合自定义校验),你设置的200L是合法的,但如果没设置就会报错。
可以在测试中添加打印响应的步骤,获取具体的错误信息:
mockMvc.perform(patch("/api/issuers/100/reassign-sales-orders") .contentType(MediaType.APPLICATION_JSON_UTF8).accept(MediaType.APPLICATION_JSON_UTF8) .content(mapper.writeValueAsString(lSalesOrderUpdateRequest))) .andDo(print()) // 打印完整的请求和响应详情 .andExpect(status().isOk());
通过打印的响应内容,你能看到具体是哪个字段校验失败,然后针对性修正测试数据即可。
3. 确认请求路径是否匹配
另外,注意控制器的路径是/issuers/{issuerId}/reassign-sales-orders,而测试中用的是/api/issuers/100/reassign-sales-orders。如果你的应用配置了server.servlet.context-path=/api的全局前缀,那没问题;如果没有,路径不匹配会返回404,但这里是400,所以这个可能性较低,不过也可以快速确认一下。
总结
优先解决MockMvc缺少校验器的问题,这是最常见的触发原因;如果问题还存在,通过打印响应排查具体的校验失败字段,最后确认请求路径是否一致。
内容的提问来源于stack exchange,提问作者Mithlesh Singh

