Интеграционное тестирование весной

Интеграционное тестирование весной

1. обзор

Интеграционное тестирование играет важную роль в цикле разработки приложений, проверяя сквозное поведение системы.

В этой статье мы увидим, как мы можем использовать тестовую среду Spring MVC для написания и запуска интеграционных тестов, которые тестируют контроллеры без явного запуска контейнера сервлета.

2. подготовка

Следующие зависимости Maven необходимы для запуска интеграционных тестов, как описано в этой статье. Прежде всего, последние зависимостиJUnit иSpring test:


    junit
    junit
    4.12
    test


    org.springframework
    spring-test
    4.3.2.RELEASE
    test

Для эффективного утверждения результатов мы также будем использоватьHamcrest иJSON path:


    org.hamcrest
    hamcrest-library
    1.3
    test


    com.jayway.jsonpath
    json-path
    2.2.0
    test

3. Конфигурация теста Spring MVC

Теперь расскажем, как настроить и запустить тесты с поддержкой Spring.

3.1. Включить Spring в тестах

Во-первых, любой тест с включенной Spring будет запускаться с помощью@RunWith(SpringJUnit4ClassRunner.class); бегун, по сути, является отправной точкой для начала использования среды Spring Test.

Нам также нужны аннотации@ContextConfiguration для загрузки конфигурации контекста иbootstrap the context that the test will use.

Давайте посмотрим:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { ApplicationConfig.class })
@WebAppConfiguration
public class GreetControllerIntegrationTest {
    ....
}

Обратите внимание, как в@ContextConfiguration, мы предоставили класс конфигурацииApplicationConfig.class, который загружает конфигурацию, необходимую для этого конкретного теста.

Мы использовали класс конфигурации Java здесь, чтобы указать конфигурацию контекста; аналогично мы можем использовать конфигурацию на основе XML:

@ContextConfiguration(locations={""})

Наконец, тест также помечен@WebAppConfiguration – which will load the web application context.

По умолчанию он ищет корневое веб-приложение по пути по умолчаниюsrc/main/webapp; местоположение можно изменить, передав аргумент значения как:

@WebAppConfiguration(value = "")

3.2. ОбъектWebApplicationContext

WebApplicationContext (wac) предоставляет конфигурацию веб-приложения. Он загружает все компоненты приложения и контроллеры в контекст.

Теперь мы можем подключить контекст веб-приложения прямо к тесту:

@Autowired
private WebApplicationContext wac;

3.3. Имитация компонентов веб-контекста

MockMvc обеспечивает поддержку тестирования Spring MVC. Он инкапсулирует все компоненты веб-приложения и делает их доступными для тестирования.

Давайте посмотрим, как это использовать:

private MockMvc mockMvc;
@Before
public void setup() throws Exception {
    this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
}

Нам нужно инициализировать объектmockMvc в аннотированном методе@Before, чтобы нам не нужно было инициализировать его внутри каждого теста.

3.4. Проверить конфигурацию теста

В нашем руководстве давайте действительно проверим, правильно ли мы загружаем объектWebApplicationContext (wac). Мы также проверим, что правильныйservletContext прикреплен:

@Test
public void givenWac_whenServletContext_thenItProvidesGreetController() {
    ServletContext servletContext = wac.getServletContext();

    Assert.assertNotNull(servletContext);
    Assert.assertTrue(servletContext instanceof MockServletContext);
    Assert.assertNotNull(wac.getBean("greetController"));
}

Обратите внимание, что мы также проверяем, существует ли bean-компонентGreetController.java в веб-контексте, что обеспечивает правильную загрузку компонентов Spring.

На этом этапе настройка интеграционного теста завершена. Давайте посмотрим, как мы можем тестировать методы ресурсов с помощью объектаMockMvc.

4. Написание интеграционных тестов

В этом разделе мы рассмотрим основные операции, доступные в тестовой среде.

Мы покажем, как отправлять запросы с переменными пути и параметрами. Кроме того, мы рассмотрим несколько примеров, которые показывают, как утверждать, что правильное имя представления разрешено или что тело ответа соответствует ожиданиям.

Следующие ниже фрагменты используют статический импорт из классов MockMvcRequestBuilders илиMockMvcResultMatchers.

4.1. Проверить имя просмотра

Давайте вызовем конечную точку/homePage из нашего теста как:

http://localhost:8080/spring-mvc-test/

or

http://localhost:8080/spring-mvc-test/homePage

Фрагмент кода:

@Test
public void givenHomePageURI_whenMockMVC_thenReturnsIndexJSPViewName() {
    this.mockMvc.perform(get("/homePage")).andDo(print())

      .andExpect(view().name("index"));
}

Давайте разберемся с этим:

  • Методperform() вызовет метод запроса получения, который вернетResultActions. Используя этот результат, у нас могут быть ожидания подтверждения ответа, такого как контент, статус HTTP, заголовок и т. Д.

  • andDo(print()) напечатает запрос и ответ. Это полезно для детального просмотра в случае ошибки

  • andExpect() будет ожидать указанный аргумент. В нашем случае мы ожидаем, что «index» будет возвращен черезMockMvcResultMatchers.view()

4.2. Проверить тело ответа

Мы будем вызывать конечную точку/greet из нашего теста как:

http://localhost:8080/spring-mvc-test/greet

Ожидаемый результат:

{
    "id": 1,
    "message": "Hello World!!!"
}

Фрагмент кода:

@Test
public void givenGreetURI_whenMockMVC_thenVerifyResponse() {
    MvcResult mvcResult = this.mockMvc.perform(get("/greet"))
      .andDo(print()).andExpect(status().isOk())
      .andExpect(jsonPath("$.message").value("Hello World!!!"))
      .andReturn();

    Assert.assertEquals("application/json;charset=UTF-8",
      mvcResult.getResponse().getContentType());
}

Посмотрим, что именно происходит:

  • andExpect(MockMvcResultMatchers.status().isOk()) проверит, что статус HTTP ответа равенOk, т.е. 200. Это гарантирует, что запрос был успешно выполнен

  • andExpect(MockMvcResultMatchers.jsonPath(“$.message”).value(“Hello World!!!”)) проверит соответствие содержания ответа аргументу «Hello World!!!». Здесь мы использовалиjsonPath, который извлекает содержимое ответа и предоставляет запрошенное значение.

  • andReturn() вернет объектMvcResult, который используется, когда нам нужно проверить что-то, что недостижимо для библиотеки. Вы можете видеть, что мы добавилиassertEquals, чтобы соответствовать типу содержимого ответа, извлеченного из объектаMvcResult

4.3. Отправить запросGET с переменной пути

Мы будем вызывать конечную точку/greetWithPathVariable/{name} из нашего теста как:

http://localhost:8080/spring-mvc-test/greetWithPathVariable/John

Ожидаемый результат:

{
    "id": 1,
    "message": "Hello World John!!!"
}

Фрагмент кода:

@Test
public void givenGreetURIWithPathVariable_whenMockMVC_thenResponseOK() {
    this.mockMvc
      .perform(get("/greetWithPathVariable/{name}", "John"))
      .andDo(print()).andExpect(status().isOk())

      .andExpect(content().contentType("application/json;charset=UTF-8"))
      .andExpect(jsonPath("$.message").value("Hello World John!!!"));
}

MockMvcRequestBuilders.get(“/greetWithPathVariable/{name}”, “John”) отправит запрос как «/greetWithPathVariable/John».

Это становится проще с точки зрения читабельности и знания параметров, которые динамически устанавливаются в URL. Этот метод не ограничивает передачу количества параметров пути.

4.4. Отправить запросGET с параметрами запроса

Мы будем вызывать конечную точку/greetWithQueryVariable?name={name} из нашего теста как:

http://localhost:8080/spring-mvc-test
  /greetWithQueryVariable?name=John%20Doe

Ожидаемый результат:

{
    "id": 1,
    "message": "Hello World John Doe!!!"
}

Фрагмент кода:

@Test
public void givenGreetURIWithQueryParameter_whenMockMVC_thenResponseOK() {
    this.mockMvc.perform(get("/greetWithQueryVariable")
      .param("name", "John Doe")).andDo(print()).andExpect(status().isOk())
      .andExpect(content().contentType("application/json;charset=UTF-8"))
      .andExpect(jsonPath("$.message").value("Hello World John Doe!!!"));
}

param(“name”, “John Doe”) добавит параметр запроса в запросGET. Это похоже на «/greetWithQueryVariable?name=John%20Doe“.

Параметр запроса также может быть реализован с использованием стиля шаблона URI:

this.mockMvc.perform(
  get("/greetWithQueryVariable?name={name}", "John Doe"));

4.5. Отправить запросPOST

Мы будем вызывать конечную точку/greetWithPost из нашего теста как:

http://localhost:8080/spring-mvc-test/greetWithPost

Ожидаемый результат:

{
    "id": 1,
    "message": "Hello World!!!"
}

Фрагмент кода:

@Test
public void givenGreetURIWithPost_whenMockMVC_thenVerifyResponse() {
    this.mockMvc.perform(post("/greetWithPost")).andDo(print())
      .andExpect(status().isOk()).andExpect(content()
      .contentType("application/json;charset=UTF-8"))
      .andExpect(jsonPath("$.message").value("Hello World!!!"));
}

MockMvcRequestBuilders.post(“/greetWithPost”) отправит почтовый запрос. Переменные пути и параметры запроса могут быть установлены аналогично тому, как мы смотрели ранее, тогда как данные формы могут быть установлены с помощью методаparam() только аналогично параметру запроса, как:

http://localhost:8080/spring-mvc-test/greetWithPostAndFormData

Данные формы:

id=1;name=John%20Doe

Ожидаемый результат:

{
    "id": 1,
    "message": "Hello World John Doe!!!"
}

Фрагмент кода:

@Test
public void givenGreetURIWithPostAndFormData_whenMockMVC_thenResponseOK() {
    this.mockMvc.perform(post("/greetWithPostAndFormData").param("id", "1")
      .param("name", "John Doe")).andDo(print()).andExpect(status().isOk())

      .andExpect(content().contentType("application/json;charset=UTF-8"))
      .andExpect(jsonPath("$.message").value("Hello World John Doe!!!"))
      .andExpect(jsonPath("$.id").value(1));
}

В приведенном выше фрагменте кода мы добавили 2 параметра id как «1» и имя как «John Doe».

5. Заключение

В этом кратком руководстве мы реализовали несколько простых интеграционных тестов с поддержкой Spring.

Мы также рассмотрели создание объектовWebApplicationContext иMockMVC, которые сыграли важную роль в вызове конечных точек приложения.

Заглянув далее, мы рассмотрели, как мы можем отправить запросGET иPOST с различными вариантами передачи параметров и как проверить статус ответа HTTP, заголовок и содержимое.

Наконец, реализация всех этих примеров и фрагментов кода доступна вhttps://github.com/eugenp/tutorials/tree/master/spring-mvc-java.