繁体   English   中英

为什么 MockMvc 请求在测试成功时检索空的 responseBody?

[英]Why MockMvc request retrieve empty responseBody while test succeed?

我正在尝试测试我的 Spring 引导 rest controller,以检查如果 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

但我找不到一种方法来测试我的错误 map 是否包含我预期的字段。 当我尝试使用以下命令检索响应正文时:

String result = mvcResult.getResponse().getContentAsString();

字符串为空,我找不到任何测试响应正文的方法。

我完全不知道,一些帮助将不胜感激!

非常感谢 !

当您使用 builder 配置 MockMvc 实例时,请进行以下更新:

MockMvcBuilders
    .standaloneSetup(controller)
    .setControllerAdvice(new ExceptionControllerAdvice())
    .build()

您应该手动将 controller 建议设置为模拟 mvc 上下文,否则将被忽略。 此更新后,您将收到正文错误响应。 如果要验证 Json 主体,请使用 json 路径 API ,如上面的答案。

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);
            }
        }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM