Почему Mock Mvc запрос извлекает пустой responseBody при успешном выполнении теста? - PullRequest
2 голосов
/ 27 мая 2020

Я пытаюсь протестировать свой контроллер отдыха Spring Boot, чтобы проверить, есть ли ошибки при отправке запроса, если проверка bean-компонента не выполняется. У меня есть пользовательский обработчик исключений с аннотацией @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"
    }
}

Я пытаюсь использовать макет Mvc для проверки поведения с помощью этого тестового класса:

@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();

, строка пуста, и я не могу найти никакого способа проверить тело ответа.

Я полностью вне идея, некоторая помощь будет принята с благодарностью!

Большое спасибо!

Ответы [ 2 ]

2 голосов
/ 27 мая 2020

Когда вы настраиваете экземпляр Mock Mvc с помощью построителя, пожалуйста, сделайте следующие обновления:

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

Вы должны вручную настроить совет контроллера на имитацию контекста mvc, в противном случае он игнорируется. После этого обновления вы получите сообщение об ошибке. Если вы хотите проверить тело Json, используйте API пути json, как в ответах выше.

1 голос
/ 27 мая 2020
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);
            }
        }
...