为什么 MockMvc 请求在测试成功时检索空的 responseBody?
Why MockMvc request retrieve empty responseBody while test succeed?
我正在尝试测试我的 Spring Boot rest 控制器,以检查在 bean 验证失败时请求是否发送属性错误。
我有一个@RestController:
@RestController
@RequestMapping("/restaurants")
public class RestaurantsApiController {
private final RestaurantService restaurantService;
private final ProductRepository productRepository;
private final ProductMapper productMapper;
public RestaurantsApiController(RestaurantService restaurantService, ProductRepository productRepository, ProductMapper productMapper) {
this.restaurantService = restaurantService;
this.productRepository = productRepository;
this.productMapper = productMapper;
}
@PostMapping("{id}/products")
public ResponseEntity<ProductDto> addProduct(@PathVariable Long id,
@Valid @RequestBody ProductDto productDto){
Product product = this.restaurantService.addProduct(id, productMapper.productDtoToProduct(productDto));
return new ResponseEntity<>(productMapper.productToProductDto(product), HttpStatus.CREATED);
}
我有一个带有@ControllerAdvice 注释的自定义异常处理程序:
@ControllerAdvice
public class ExceptionControllerAdvice {
@ExceptionHandler({MethodArgumentNotValidException.class})
public ResponseEntity<Object> validationException(MethodArgumentNotValidException ex, WebRequest request) {
....
// here i format my custom error message
return new ResponseEntity<>(apiError, new HttpHeaders(), apiError.getStatus());
}
效果很好,如果验证失败,会向我发送此自定义响应:
{
"status": "BAD_REQUEST",
"errors": {
"price": "doit être supérieur ou égal à 0",
"name": "ne doit pas être nul",
"category": "ne doit pas être nul"
}
}
我正在尝试使用 mockMvc 来测试此测试的行为 class :
@ExtendWith(MockitoExtension.class)
class RestaurantsApiControllerTest {
@Mock
private RestaurantService restaurantService;
@Mock
private ProductRepository productRepository;
@Mock
private ProductMapper productMapper;
@InjectMocks
private RestaurantsApiController controller;
MockMvc mockMvc;
@BeforeEach
void setUp() {
mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
}
@Test
void givenInvalidFrom_whenAddProduct_ThenShouldThrowException() throws Exception {
// productDto miss name, category and have negative value for price which is forbidden by validations annotations
ProductDto productDto = ProductDto.builder().id(1L).price(-10.5D).build();
MvcResult mvcResult = mockMvc.perform(post("/restaurants/1/products")
.contentType(MediaType.APPLICATION_JSON)
.content(asJsonString(productDto)))
.andExpect(status().isBadRequest())
.andReturn();
String result = mvcResult.getResponse().getContentAsString();
then(restaurantService).shouldHaveNoInteractions();
}
测试完美通过,我可以在日志中看到正确预期的验证异常:
14:53:30.345 [main] WARN org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver - Resolved [org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument ...
//I removed the rest of the message for readability, but each validation exception appears here properly
14:53:30.348 [main] DEBUG org.springframework.test.web.servlet.TestDispatcherServlet - Completed 400 BAD_REQUEST
但我找不到一种方法来测试我的错误图是否包含我期望的字段。当我尝试使用 :
检索响应正文时
String result = mvcResult.getResponse().getContentAsString();
字符串为空,我找不到任何测试响应正文的方法。
我完全不知道,如果能提供帮助,我们将不胜感激!
非常感谢!
MvcResult mvcResult = mockMvc.perform(post("/restaurants/1/products")
.contentType(MediaType.APPLICATION_JSON)
.content(asJsonString(productDto)))
.andExpect(status().isBadRequest())
.andExpect(content().string("Your content"))
.andReturn();
或使用自定义匹配器
MvcResult mvcResult = mockMvc.perform(post("/restaurants/1/products")
.contentType(MediaType.APPLICATION_JSON)
.content(asJsonString(productDto)))
.andExpect(status().isBadRequest())
.andExpect(content().string(new CustomMatcher()))
.andReturn();
private static class ContentMatcher extends CustomMatcher<String>{
public ContentMatcher() {
super("");
}
@Override
public boolean matches(Object o) {
final String expected="Some long wide string " +
"wich i should check" +
"...."
return o.equals(expected);
}
}
当您使用构建器配置 MockMvc 实例时,请进行以下更新:
MockMvcBuilders
.standaloneSetup(controller)
.setControllerAdvice(new ExceptionControllerAdvice())
.build()
您应该手动将控制器建议设置为模拟 mvc 上下文,否则将被忽略。
此次更新后,您将在错误响应中收到正文。如果你想验证 Json 正文,请使用 json 路径 API 就像上面的答案一样。
我正在尝试测试我的 Spring Boot rest 控制器,以检查在 bean 验证失败时请求是否发送属性错误。
我有一个@RestController:
@RestController
@RequestMapping("/restaurants")
public class RestaurantsApiController {
private final RestaurantService restaurantService;
private final ProductRepository productRepository;
private final ProductMapper productMapper;
public RestaurantsApiController(RestaurantService restaurantService, ProductRepository productRepository, ProductMapper productMapper) {
this.restaurantService = restaurantService;
this.productRepository = productRepository;
this.productMapper = productMapper;
}
@PostMapping("{id}/products")
public ResponseEntity<ProductDto> addProduct(@PathVariable Long id,
@Valid @RequestBody ProductDto productDto){
Product product = this.restaurantService.addProduct(id, productMapper.productDtoToProduct(productDto));
return new ResponseEntity<>(productMapper.productToProductDto(product), HttpStatus.CREATED);
}
我有一个带有@ControllerAdvice 注释的自定义异常处理程序:
@ControllerAdvice
public class ExceptionControllerAdvice {
@ExceptionHandler({MethodArgumentNotValidException.class})
public ResponseEntity<Object> validationException(MethodArgumentNotValidException ex, WebRequest request) {
....
// here i format my custom error message
return new ResponseEntity<>(apiError, new HttpHeaders(), apiError.getStatus());
}
效果很好,如果验证失败,会向我发送此自定义响应:
{
"status": "BAD_REQUEST",
"errors": {
"price": "doit être supérieur ou égal à 0",
"name": "ne doit pas être nul",
"category": "ne doit pas être nul"
}
}
我正在尝试使用 mockMvc 来测试此测试的行为 class :
@ExtendWith(MockitoExtension.class)
class RestaurantsApiControllerTest {
@Mock
private RestaurantService restaurantService;
@Mock
private ProductRepository productRepository;
@Mock
private ProductMapper productMapper;
@InjectMocks
private RestaurantsApiController controller;
MockMvc mockMvc;
@BeforeEach
void setUp() {
mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
}
@Test
void givenInvalidFrom_whenAddProduct_ThenShouldThrowException() throws Exception {
// productDto miss name, category and have negative value for price which is forbidden by validations annotations
ProductDto productDto = ProductDto.builder().id(1L).price(-10.5D).build();
MvcResult mvcResult = mockMvc.perform(post("/restaurants/1/products")
.contentType(MediaType.APPLICATION_JSON)
.content(asJsonString(productDto)))
.andExpect(status().isBadRequest())
.andReturn();
String result = mvcResult.getResponse().getContentAsString();
then(restaurantService).shouldHaveNoInteractions();
}
测试完美通过,我可以在日志中看到正确预期的验证异常:
14:53:30.345 [main] WARN org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver - Resolved [org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument ...
//I removed the rest of the message for readability, but each validation exception appears here properly
14:53:30.348 [main] DEBUG org.springframework.test.web.servlet.TestDispatcherServlet - Completed 400 BAD_REQUEST
但我找不到一种方法来测试我的错误图是否包含我期望的字段。当我尝试使用 :
检索响应正文时String result = mvcResult.getResponse().getContentAsString();
字符串为空,我找不到任何测试响应正文的方法。
我完全不知道,如果能提供帮助,我们将不胜感激!
非常感谢!
MvcResult mvcResult = mockMvc.perform(post("/restaurants/1/products")
.contentType(MediaType.APPLICATION_JSON)
.content(asJsonString(productDto)))
.andExpect(status().isBadRequest())
.andExpect(content().string("Your content"))
.andReturn();
或使用自定义匹配器
MvcResult mvcResult = mockMvc.perform(post("/restaurants/1/products")
.contentType(MediaType.APPLICATION_JSON)
.content(asJsonString(productDto)))
.andExpect(status().isBadRequest())
.andExpect(content().string(new CustomMatcher()))
.andReturn();
private static class ContentMatcher extends CustomMatcher<String>{
public ContentMatcher() {
super("");
}
@Override
public boolean matches(Object o) {
final String expected="Some long wide string " +
"wich i should check" +
"...."
return o.equals(expected);
}
}
当您使用构建器配置 MockMvc 实例时,请进行以下更新:
MockMvcBuilders
.standaloneSetup(controller)
.setControllerAdvice(new ExceptionControllerAdvice())
.build()
您应该手动将控制器建议设置为模拟 mvc 上下文,否则将被忽略。 此次更新后,您将在错误响应中收到正文。如果你想验证 Json 正文,请使用 json 路径 API 就像上面的答案一样。