Тестирование Spring-контроллеров путем (псевдо) прямого вызова этого метода-обработчика - хорошо или плохо? как это реализовать? - PullRequest
0 голосов
/ 08 марта 2020

В одном предложении: Я хочу, чтобы MockMvc работал так, как если бы я напрямую вызывал контроллер .

(PS Это синтаксический сахар Это не означает Я действительно вызываю контроллеры, когда интеграционный тест .)


Подробности:

Скажем, у нас есть контроллер Restful:

class BookController {
    public Book updateBook(int id, Book newBook) {...}
}

Типичное пружинное интеграционное тестирование для службы RESTful выглядит следующим образом:

mockMvc.perform(put("/books/1")
                .content("{\"id\":1, \"name\": \"ABC\", ...}")
                .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON))
                .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.id", is(1)))
                .andExpect(jsonPath("$.name", is("ABC")))
                ...and more...;

Однако можем ли мы делать такие вещи, как:

BookController magicBookController = SomeMagic.generate_the_magic_controller();
Book result = magicMvc.perform(magicBookController.updateBook(1, new Book("ABC", ...)));
assertThat(1, result.getId());
assertThat("ABC", result.getName());
...

РЕДАКТИРОВАТЬ : код выше , а не , просто вызывая метод new BookController().updateBook(...)! Я надеюсь, что generate_the_magic_controller будет генерировать динамические прокси c (используя cglib). Затем, когда мы вызываем magicBookController.updateBook, фактически динамически сгенерированный код выглядит следующим образом:

Book dynamically_generated_updateBook(int id, Book book) {
    String url = magic_assemble_url(id); // will become: "/books/1"
    String content = magic_assemble_content(book); // will become: "{name: AAA, ...}"
    Something result = mockMvc.perform(put(url)
                .content(content)
                .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON));
    return parse_result(result); //parse back into book
}

В одном предложении: Я хочу, чтобы MockMvc работал так, как если бы я был прямой вызов контроллера . Мой вопрос:

  1. Должен ли я это сделать? (Или это очень плохая практика?)
  2. Как это сделать? Я собираюсь взломать часть в среде Spring о «поиске и разборе контроллеров», но у меня нет конкретных идей о том, как это сделать ...

РЕДАКТИРОВАТЬ : My Цель тестирования заключается в следующем. Изначально людям нравилось тестировать код своими глазами (давать входные данные, смотреть на результаты и утверждать их умом). Конечно, это плохо. Поэтому мы записываем такие вещи, как «опубликовать в / books и заявить, что результаты верны». Это то, что я хочу проверить. Это на самом деле немного похоже на тест E2E (так как это спокойный сервис) ИМХО. (Или моя цель полностью неверна?)


РЕДАКТИРОВАТЬ : Типичный тест в Джерси, который, как мне кажется (лично), более элегантен, чем тесты в Спринге:

Profile profile = resources.getJerseyTest()
                              .target("/v1/profile/" + AuthHelper.VALID_NUMBER_TWO)
                              .request()
                              .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
                              .get(Profile.class);
assertEquals(profile.getXXX(), "aaa");
...

Большое спасибо за любые идеи!

1 Ответ

0 голосов
/ 08 марта 2020

Смысл MockMvc состоит в том, чтобы проверить правильность настройки REST API с использованием инфраструктуры spring- mvc, такой как вещи, к которым может быть привязан HTTP-запрос, и вызвать ожидаемый метод контроллера с правильными параметрами, * Объект 1013 *, возвращаемый методом контроллера, может быть сериализован в правильное тело JSON в ответе HTTP et c. Речь идет о проверке правильности поведения REST API при HTTP-запросе, поэтому вы должны указать HTTP-запрос, если хотите использовать MockMvc

Мне кажется, что вы хотите протестировать свой клиент для отдыха, такой как такие вещи, как он, могут отправлять запрос на ожидаемый URL с ожидаемым телом и десериализовать ответ JSON обратно на java объект et c. вместо того, чтобы проверять, правильно ли настроен ваш REST API. Если да, вы можете заглушить REST API с помощью таких инструментов, как Wiremock или okhttp MockWebServer, и как обычно использовать оставшийся клиент для вызова заглушки API.

Итак, первое, о чем вы должны спросить, это то, что какую вещь вы хотите проверить на самом деле? Обычно мы фокусируемся только на тестировании одной вещи каждый раз И лучше указывать входные данные теста напрямую и декларативно без каких-либо сложных преобразований кода, таких как преобразование некоторых заданных входных данных во входные данные, которые действительно необходимы для теста, так как большее количество кодов преобразования означает больше шансов внести другой аспект ошибки.

Так что, если вы хотите проверить, правильно ли вы настраиваете API Spring- mvc (то есть, используя mock Mvc), плохая идея реализовать что-то, что преобразует ваш сгенерированный клиент rest в запрос HTTP, который на самом деле необходимо вызвать API.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...