我有以下 Spring 测试类:
@AutoConfigureMockMvc
@Testcontainers
@ExtendWith(SpringExtension.class)
@SpringBootTest
@ActiveProfiles("test")
public class FormTest {
@Autowired
private MockMvc mockMvc;
@Test
public void givenInvalidForm_whenSubmitted_returns400() throws Exception {
FormUploadDTO dto = .. generate DTO
MvcResult mvcResult = mockMvc.perform(post(BaseApi.BASE_API + "/forms")
.contentType(MediaType.APPLICATION_JSON.getMediaType())
.content(asJsonString(new ArrayList<>(Collections.singleton(dto)){}))
.andDo(print())
.andReturn();
assertEquals(400, mvcResult.getResponse().getStatus());
}
}
但是,spring-application 容器没有返回错误请求(对于
@NotNull
带注释的字段),而是抛出以下错误:
jakarta.servlet.ServletException: Request processing failed: jakarta.validation.ConstraintViolationException: submitForm.dtos[0].client: must not be null, submitForm.dtos[0].priceType: must not be null, submitForm.dtos[0].price: must not be null, submitForm.dtos[0].materialType: must not be null, submitForm.dtos[0].dateTo: must not be null, submitForm.dtos[0].client: must not be blank, submitForm.dtos[0].dateFrom: must not be null
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1019)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:914)
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:590)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885)
at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:72)
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)
at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter ....
Caused by: jakarta.validation.ConstraintViolationException: submitForm.dtos[0].client: must not be null, submitForm.dtos[0].priceType: must not be null, submitForm.dtos[0].price: must not be null, submitForm.dtos[0].materialType: must not be null, submitForm.dtos[0].dateTo: must not be null, submitForm.dtos[0].client: must not be blank, submitForm.dtos[0].dateFrom: must not be null
at org.springframework.validation.beanvalidation.MethodValidationInterceptor.invoke(MethodValidationInterceptor.java:138)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:756)
知道如何解决这个问题吗?
如果
MockMvc#perform()
抛出异常,则意味着您没有配置 spring-mvc 来处理此异常。(即您的情况下的 ConstraintViolationException
)。
实际上,异常将被传播回 Servlet 容器,让它处理将返回的 HTTP 响应。现在,当您使用
MockMvc
时,您可以认为 MockMvc
是一种 Servlet 容器,它的实现将简单地抛出从 spring-mvc 传播到它的任何异常。
所以答案是配置 spring-mvc 来处理
ConstraintViolationException
,例如为其声明一个 @ControllerAdvice
:
@ControllerAdvice
public class ApiExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler(ConstraintViolationException.class)
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
public void handleConstraintViolationException(final ConstraintViolationException ex) {
log.info("handle ConstraintViolationException blabla",ex);
}
}
注意:请参阅this
了解如何在 spring-mvc 中处理异常