Maven - самый популярный инструмент сборки в пространстве Java, а интеграционное тестирование - неотъемлемая часть процесса разработки. Следовательно,it’s a natural choice to configure and execute integration tests with Maven.
В этом руководстве мы рассмотрим несколько различных способов использования Maven для интеграционного тестирования и отделения интеграционных тестов от модульных.
2. подготовка
Чтобы приблизить демонстрационный код к реальному проекту, мы создадим приложение JAX-RS. Это приложение развертывается на сервере перед выполнением интеграционных тестов и затем демонтируется.
2.1. Конфигурация Maven
Мы создадим наше приложение REST на основе Джерси - эталонной реализации JAX-RS. Эта реализация требует пару зависимостей:
Мы можем найти последние версии этих зависимостейhere иhere.
Мы будем использовать плагин Jetty Maven для настройки тестовой среды. This plugin starts a Jetty server during the pre-integration-test phase of the Maven build lifecycle, then stops it in the post-integration-test phase.с
Вот как мы настраиваем плагин Jetty Maven вpom.xml:
Когда сервер Jetty запускается, он будет прослушивать порт8999. Элементы конфигурацииstopKey иstopPort используются исключительно для цели плагинаstop, и их значение с нашей точки зрения не имеет значения.
Here - это место, где можно найти последнюю версию плагина Jetty Maven.
Также следует отметить, что мы должны установить для элементаpackaging в файлеpom.xml значениеwar, иначе плагин Jetty не сможет запустить сервер:
war
2.2. Создание приложения REST
Конечная точка приложения очень проста - возвращает приветственное сообщение, когда запрос GET попадает в корневой контекст:
@Path("/")
public class RestEndpoint {
@GET
public String hello() {
return "Welcome to example!";
}
}
Вот как мы регистрируем класс конечной точки в Джерси:
package com.example.maven.it;
import org.glassfish.jersey.server.ResourceConfig;
public class EndpointConfig extends ResourceConfig {
public EndpointConfig() {
register(RestEndpoint.class);
}
}
Чтобы сервер Jetty знал о нашем приложении REST, мы можем использовать классический дескриптор развертыванияweb.xml:
This descriptor must be placed in the directory /src/main/webapp/WEB-INF для распознавания сервером.
2.3. Клиентский тестовый код
Все тестовые классы в следующих разделах содержат один метод:
@Test
public void whenSendingGet_thenMessageIsReturned() throws IOException {
String url = "http://localhost:8999";
URLConnection connection = new URL(url).openConnection();
try (InputStream response = connection.getInputStream();
Scanner scanner = new Scanner(response)) {
String responseBody = scanner.nextLine();
assertEquals("Welcome to example!", responseBody);
}
}
Как мы видим, этот метод не делает ничего, кроме отправки запроса GET в веб-приложение, которое мы создали ранее, и проверки ответа.
3. Интеграционное тестирование в действии
При интеграционном тестировании важно отметить, чтоtest methods often take quite a long time to run.
В результате мы должны исключить интеграционные тесты из жизненного цикла сборки по умолчанию, чтобы они не замедляли весь процесс при каждом построении проекта.
A convenient way to separate integration tests is to use build profiles. Такая конфигурация позволяет нам выполнять интеграционные тесты только при необходимости - путем указания подходящего профиля.
В следующих разделах мы настроим все интеграционные тесты с профилями сборки.
По умолчанию плагин Mavensurefire выполняет модульные тесты на этапеtest, аthe failsafe plugin runs integration tests in the integration-test phase.
Мы можем назвать тестовые классы с различными шаблонами для этих плагинов, чтобы выбрать вложенные тесты отдельно.
Соглашения об именах по умолчанию, применяемыеsurefire иfailsafe, различны, поэтому нам просто нужно следовать этим соглашениям, чтобы разделить модульные и интеграционные тесты.
Выполнение плагинаsurefire включает все классы, имя которых начинается сTest или заканчивается наTest,Tests илиTestCase. Напротив, плагинfailsafe выполняет тестовые методы в классах, имя которых начинается сIT или заканчивается наIT илиITCase.
This - это то место, где мы можем найти документацию относительно включения тестов дляsurefire, аhere - дляfailsafe.
Давайте добавим плагинfailsafe в POM с конфигурацией по умолчанию:
This link - это место, где найти последнюю версию плагинаfailsafe.
В приведенной выше конфигурации на этапеintegration-test будет выполняться следующий метод тестирования:
public class RestIT {
// test method shown in subsection 2.3
}
Поскольку сервер Jetty запускается на этапеpre-integration-test и выключается черезpost-integration-test, тест, который мы только что видели, проходит с помощью этой команды:
mvn verify -Pfailsafe
Мы также можем настроить шаблоны именования для включения классов с разными именами:
Помимо плагинаfailsafe,we can also use the surefire plugin to execute unit and integration tests in different phases.
Предположим, мы хотим назвать все интеграционные тесты суффиксомIntegrationTest. Поскольку плагинsurefire по умолчанию запускает тесты с таким именем в фазеtest, нам нужно исключить их из выполнения по умолчанию:
Instead of binding the test goal of the surefire plugin to the test build phase, as usual, we bound it to the integration-test phase. Затем плагин запустится во время процесса тестирования интеграции.
Обратите внимание, что мы должны установить для элементаexclude значениеnone, чтобы переопределить исключение, указанное в базовой конфигурации.
Теперь давайте определим тестовый класс интеграции с нашим шаблоном именования:
public class RestIntegrationTest {
// test method shown in subsection 2.3
}
Этот тест будет выполняться с помощью команды:
mvn verify -Psurefire
6. Тестирование с помощью плагина Cargo
Мы можем использовать плагинsurefire с плагином Mavencargo. Этот плагин поставляется со встроенной поддержкой встроенных серверов, которые очень полезны для тестирования интеграции.
Более подробную информацию об этой комбинации можно найти вhere.
7. Тестирование с помощью JUnit's@Category
Удобный способ выборочного выполнения тестов - использоватьthe @Category annotation в среде JUnit 4. This annotation lets us exclude particular tests from unit testing, and include them in integration testing.
Во-первых, нам нужен интерфейс или класс для работы в качестве идентификатора категории:
package com.example.maven.it;
public interface Integration { }
Затем мы можем украсить тестовый класс аннотацией@Category и идентификаторомIntegration:
@Category(Integration.class)
public class RestJUnitTest {
// test method shown in subsection 2.3
}
Вместо того, чтобы объявлять аннотацию@Category в тестовом классе, мы также можем использовать ее на уровне метода для категоризации отдельных методов тестирования.
Теперь мы можем запустить интеграционные тесты с помощью команды Maven:
mvn verify -Pcategory
8. Добавление отдельного каталога для интеграционных тестов
Иногда желательно иметь отдельный каталог для интеграционных тестов. Organizing tests this way allows us to entirely isolate integration tests from unit tests.с
Для этого мы можем использовать плагин Mavenbuild helper:
Here - это место, где мы можем найти последнюю версию этого плагина.
Конфигурация, которую мы только что видели, добавляет в сборку каталог с исходным кодом теста. Давайте добавим определение класса в этот новый каталог:
public class RestITCase {
// test method shown in subsection 2.3
}
Пришло время запустить интеграционные тесты в этом классе:
mvn verify -Pfailsafe
Плагин Mavenfailsafe будет выполнять методы в этом тестовом классе из-за конфигурации, которую мы установили в подразделе 3.1.
Каталог с тестовым исходным кодом часто идет вместе с каталогом ресурсов. Мы можем добавить такой каталог в другой элементexecution в конфигурацию плагина:
В этой статье мы рассмотрели использование Maven для запуска интеграционных тестов с сервером Jetty, уделяя особое внимание настройке плагинов Mavensurefire иfailsafe.
Полный исходный код этого руководства можно найти наover on GitHub.