Перейти к основному содержимому

Изучение среды тестирования Джерси

· 6 мин. чтения

1. Обзор

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

Как мы уже видели в предыдущих статьях, Jersey — это платформа с открытым исходным кодом для разработки RESTful Web Services . Мы можем узнать больше о Джерси в нашей статье «Введение в создание API с помощью Джерси и Spring» — здесь .

2. Настройка приложения

Jersey Test Framework — это инструмент, помогающий нам проверить правильность реализации наших серверных компонентов. Как мы увидим позже, он обеспечивает быстрый и простой способ написания интеграционных тестов и очень хорошо справляется с взаимодействием с нашими HTTP API.

Точно так же он работает практически «из коробки» и его легко интегрировать с нашими проектами на базе Maven . Фреймворк в основном основан на JUnit, хотя его также можно использовать с TestNG, что делает его пригодным для использования практически во всех средах.

В следующем разделе мы увидим, какие зависимости нам нужно добавить в наше приложение, чтобы использовать фреймворк.

2.1. Зависимости Maven

Прежде всего, давайте добавим базовую зависимость Jersey Test Framework в наш pom.xml :

<dependency>
<groupId>org.glassfish.jersey.test-framework</groupId>
<artifactId>jersey-test-framework-core</artifactId>
<version>2.27</version>
<scope>test</scope>
</dependency>

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

Почти все тесты на Джерси используют де-факто тестовую фабрику контейнеров Grizzly, которую нам также нужно будет добавить:

<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-grizzly2</artifactId>
<version>2.27</version>
<scope>test</scope>
</dependency>

Снова последнюю версию мы можем найти в Maven Central .

3. Начало работы

В следующем разделе мы рассмотрим основные шаги, необходимые для написания простого теста.

Начнем с тестирования простого ресурса Greetings на нашем сервере:

@Path("/greetings")
public class Greetings {

@GET
@Path("/hi")
public String getHiGreeting() {
return "hi";
}
}

3.1. Настройка теста

Теперь давайте определим наш тестовый класс:

public class GreetingsResourceIntegrationTest extends JerseyTest {

@Override
protected Application configure() {
return new ResourceConfig(Greetings.class);
}
//...
}

В приведенном выше примере мы видим, что для разработки теста с использованием Jersey Test Framework наш тест должен быть подклассом JerseyTest .

Затем мы переопределяем метод configure , который возвращает пользовательскую конфигурацию ресурса для нашего теста и содержит только ресурс Greetings . Это, конечно, тот ресурс, который мы хотим протестировать.

3.2. Пишем наш первый тест

Давайте начнем с тестирования простого запроса GET от нашего API приветствия:

@Test
public void givenGetHiGreeting_whenCorrectRequest_thenResponseIsOkAndContainsHi() {
Response response = target("/greetings/hi").request()
.get();

assertEquals("Http Response should be 200: ", Status.OK.getStatusCode(), response.getStatus());
assertEquals("Http Content-Type should be: ", MediaType.TEXT_HTML, response.getHeaderString(HttpHeaders.CONTENT_TYPE));

String content = response.readEntity(String.class);
assertEquals("Content of ressponse is: ", "hi", content);
}

Обратите внимание, что у нас есть полный доступ к ответу HTTP , поэтому мы можем выполнять такие действия, как проверка кода состояния, чтобы убедиться, что операция действительно прошла успешно, или работать с фактическим телом ответа .

Поясним подробнее, что мы делаем в приведенном выше примере:

  1. Отправьте запрос HTTP GET на «/greetings/hi»
  2. Проверьте код состояния HTTP и заголовки ответа типа контента.
  3. Проверить содержимое ответа содержит строку «привет»

4. Тестирование GET для получения ресурсов

Теперь, когда мы увидели основные шаги, связанные с созданием тестов. Давайте протестируем простой Fruit API, который мы представили в отличной статье Jersey MVC Support .

4.1. Получите обычный JSON

В приведенном ниже примере мы работаем с телом ответа как со стандартной строкой JSON:

@Test
public void givenFruitExists_whenSearching_thenResponseContainsFruit() {
final String json = target("fruit/search/strawberry").request()
.get(String.class);
assertThat(json, containsString("{\"name\":\"strawberry\",\"weight\":20}"));
}

4.2. Получить сущность вместо JSON

Мы также можем сопоставить ответ непосредственно с классом сущности Resource, например:

@Test
public void givenFruitExists_whenSearching_thenResponseContainsFruitEntity() {
final Fruit entity = target("fruit/search/strawberry").request()
.get(Fruit.class);

assertEquals("Fruit name: ", "strawberry", entity.getName());
assertEquals("Fruit weight: ", Integer.valueOf(20), entity.getWeight());
}

На этот раз мы указываем тип Java, в который объект ответа будет преобразован в методе get — объект Fruit .

5. Тестирование POST для создания ресурсов

Чтобы создать новый ресурс в нашем API, мы будем использовать POST-запросы. В следующем разделе мы увидим, как протестировать эту часть нашего API.

5.1. Сообщение в формате JSON

Давайте начнем с публикации простой строки JSON, чтобы проверить создание нового фруктового ресурса:

@Test
public void givenCreateFruit_whenJsonIsCorrect_thenResponseCodeIsCreated() {
Response response = target("fruit/created").request()
.post(Entity.json("{\"name\":\"strawberry\",\"weight\":20}"));

assertEquals("Http Response should be 201 ", Status.CREATED.getStatusCode(), response.getStatus());
assertThat(response.readEntity(String.class), containsString("Fruit saved : Fruit [name: strawberry colour: null]"));
}

В приведенном выше примере мы используем метод post , который принимает параметр объекта Entity . Мы используем удобный метод json для создания сущности из соответствующей строки JSON .

5.2. Опубликовать объект вместо JSON

Как мы уже видели с запросами на получение, мы также можем напрямую опубликовать класс сущности Resource, например:

@Test
public void givenCreateFruit_whenFruitIsInvalid_thenResponseCodeIsBadRequest() {
Fruit fruit = new Fruit("Blueberry", "purple");
fruit.setWeight(1);

Response response = target("fruit/create").request(MediaType.APPLICATION_JSON_TYPE)
.post(Entity.entity(fruit, MediaType.APPLICATION_JSON_TYPE));

assertEquals("Http Response should be 400 ", 400, response.getStatus());
assertThat(response.readEntity(String.class), containsString("Fruit weight must be 10 or greater"));
}

На этот раз мы используем метод сущности для публикации нашей сущности Fruit, а также указываем тип мультимедиа как JSON.

5.3. Отправка форм с использованием POST

В нашем последнем примере публикации мы увидим, как тестировать отправку формы через почтовый запрос:

@Test
public void givenCreateFruit_whenFormContainsNullParam_thenResponseCodeIsBadRequest() {
Form form = new Form();
form.param("name", "apple");
form.param("colour", null);

Response response = target("fruit/create").request(MediaType.APPLICATION_FORM_URLENCODED)
.post(Entity.form(form));

assertEquals("Http Response should be 400 ", 400, response.getStatus());
assertThat(response.readEntity(String.class), containsString("Fruit colour must not be null"));
}

Точно так же мы используем класс Entity , но на этот раз передаем форму, содержащую ряд параметров, в наш почтовый запрос.

6. Тестирование других HTTP-команд

Иногда нам нужно протестировать другие конечные точки HTTP, такие как PUT и DELETE. Это, конечно, вполне возможно, используя инфраструктуру тестирования Джерси.

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

@Test
public void givenUpdateFruit_whenFormContainsBadSerialParam_thenResponseCodeIsBadRequest() {
Form form = new Form();
form.param("serial", "2345-2345");

Response response = target("fruit/update").request(MediaType.APPLICATION_FORM_URLENCODED)
.put(Entity.form(form));

assertEquals("Http Response should be 400 ", 400, response.getStatus());
assertThat(response.readEntity(String.class), containsString("Fruit serial number is not valid"));
}

После того, как мы вызвали метод запроса , мы можем вызвать любой метод HTTP для текущего объекта запроса.

7. Дополнительные возможности

Инфраструктура тестирования Джерси содержит ряд дополнительных свойств конфигурации, которые могут помочь в отладке и тестировании.

В следующем примере мы увидим, как программно включить функцию с заданным именем:

public class FruitResourceIntegrationTest extends JerseyTest {

@Override
protected Application configure() {
enable(TestProperties.LOG_TRAFFIC);
enable(TestProperties.DUMP_ENTITY);
//...

Когда мы создаем и настраиваем наше тестируемое приложение на Джерси. Мы также можем включить дополнительные свойства. В этом случае мы включаем два свойства ведения журнала — LOG_TRAFFIC и DUMP_ENTITY , которые будут предоставлять полезную дополнительную информацию для ведения журнала и отладки во время тестовых прогонов.

8. Поддерживаемые контейнеры

Как мы уже упоминали, контейнер де-факто, используемый при написании тестов с помощью Jersey Test Framework, — это Grizzly. Однако поддерживается ряд других контейнеров:

  • Контейнер в памяти
  • HttpServer из Oracle JDK
  • Простой контейнер (org.simpleframework.http
  • Контейнер Jetty (org.eclipse.jetty)

Для получения дополнительной информации о том, как настроить эти контейнеры, см. документацию здесь .

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

Подводя итог, в этом руководстве мы изучили среду тестирования Джерси. Во-первых, мы начали с того, что рассказали, как настроить инфраструктуру тестирования Джерси, а затем увидели, как написать тест для очень простого API.

В следующем разделе мы увидели, как писать тесты для различных конечных точек GET и POST API. Наконец, мы рассмотрели некоторые дополнительные функции и контейнеры, которые поддерживает инфраструктура тестирования Джерси.

Как всегда, полный исходный код статьи доступен на GitHub .