控制器Patch方法测试时校验失效,请求报错求助
嘿,我来帮你排查这个问题。你的测试里@Valid没起到拦截无效请求的作用,反而让服务层抛出了Content must not be null!的异常,但Postman请求正常,这大概率是几个配置或代码细节没处理好,我们一步步来:
1. 先检查EditOrganizationRequest的校验注解
你测试时传了空字符串的请求体,但@Valid没触发校验,核心原因很可能是你的EditOrganizationRequest类的字段上没加对应的校验注解。Spring的@Valid是基于JSR-380规范的,需要给字段标注类似@NotBlank(针对字符串,拒绝空字符串/纯空白)、@NotEmpty这类注解才会生效。比如:
data class EditOrganizationRequest( @NotBlank(message = "组织名称不能为空") val name: String )
如果没有这些注解,@Valid根本不知道要校验什么,自然会把不符合要求的对象直接传给服务层,导致服务层的非空检查抛出异常。
2. 确认测试类的校验配置是否完整
如果你的测试用了@WebMvcTest,要确保测试上下文包含了校验相关的自动配置。有时候@WebMvcTest默认不会引入所有自动配置,你可以手动给测试类加上@Import(ValidationAutoConfiguration::class),或者直接用@SpringBootTest(它会自动加载完整的上下文,包括校验)。
举个测试类的正确配置例子:
@WebMvcTest(OrganizationController::class) @Import(ValidationAutoConfiguration::class) class OrganizationControllerTest { @Autowired lateinit var mvc: MockMvc // 你的测试方法 }
3. 控制器方法的小优化
看你的控制器代码:@Valid @RequestBody baseData: EditOrganizationRequest?然后直接用baseData!!。这里其实可以优化一下:既然你用了@Valid,可以把参数改成非空类型(去掉?),因为Spring在请求体合法时会注入非空对象,校验不通过的话会直接返回400,根本不会走到baseData!!这一步:
@PatchMapping("{id}") @ResponseStatus(HttpStatus.ACCEPTED) fun edit(@PathVariable id: Long, @Valid @RequestBody baseData: EditOrganizationRequest) = manageOrganizationService.update(id, baseData).let { EntityModel.of(it) }
这样也能避免不必要的非空断言。
最后验证
给EditOrganizationRequest加上校验注解,调整好测试配置后,重新运行你的测试,@Valid就会在进入服务层之前拦截空字符串的请求,返回400 Bad Request,测试就能通过了。
至于Postman请求正常的原因,应该是你在Postman里传的都是符合要求的参数,触发了正常的校验流程,而测试里的空字符串请求因为缺少校验注解没被提前拦截。
内容的提问来源于stack exchange,提问作者LookBad

