Интеграционное тестирование с maven. Часть 1. Запускаем wildfly во время сборки

Не будем углубляться далеко в теорию, так как по определению интеграционного тестирования пруд пруди различных статей. Вкратце, интеграционное тестирование (в дальнейшем будем сокращать до ИТ) поможет протестировать некоторый процесс нашего приложения. Например, если наше приложение проводит какие-нибудь платежи, то ИТ помогут выполнить платеж с разными данными и проверить что на выходе мы получили то, что ожидали. То есть в БД будут лежать ожидаемые данные, результатом операции будет успешный платеж и т.д. Цель таких тестов – не прогон отдельных методов или цепочки методов как при юнит тестировании, а тестирование общей логики приложения, убеждение что приложение делает то, что от него ожидают и не делает того, чего от него не ожидают.

Прежде, чем двигаться дальше, необходимо понимать общие принципы сборки проектов maven. Как минимум, необходимо знать что maven разбивает сборку на фазы. Если посмотреть на полный список фаз, то можно увидеть вот эти 3 штуки почти в самом конце сборки: pre-integration-test, integration-test и post-integration-test. Это как раз то что нам нужно. Также необходимо знать о профилях и понимать как работать с плагинами, нужно знать что у плагинов бывают цели (goals) и что эти цели можно вызывать, завязывая их на определенные стадии сборки.

Для проведения ИТ мы будем полностью поднимать окружение прямо во время сборки, то есть во время фаз ИТ, указанных выше. Нам необходимо поднять сервер, настроить его, развернуть тестовую БД, задеплоить в него необходимые модули и собственно провести тесты. То есть, с нуля поднять все, что нужно для работы приложения, как бы “с чистого листа”, чтобы быть уверенными, что на тесты не влияет окружение. В этой статье займемся стартом сервера и разворачиванием приложения во время сборки. Возьмем пример из моей первой статьи, и начнем его модифицировать.

Первым делом выделим под тесты новый maven модуль. Я назвал его просто itmodule. Далее создадим профиль, который поможет нам включать или выключать ИТ (в больших проектах ИТ занимает приличное время, поэтому не стоит прогонять его во время каждой сборки). Создать и настроить профиль можно многими способами. Например, в pom проекта добавим следующее:

<profiles>
    <profile>
        <id>it</id>
        <modules>
            <module>itmodule</module>
        </modules>
    </profile>
</profiles>

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

Теперь возьмемся за pom нашего itmodule. И по порядку: добавляем константу для версии Wildfly:

<properties>
    <wildfly.version>10.0.0.Final</wildfly.version>
</properties>

Добавляем зависимость на модуль server-ear (так как он будет деплоиться в тестовый сервер):

<dependencies>
    <dependency>
        <groupId>${project.parent.groupId}</groupId>
        <version>${project.parent.version}</version>
        <artifactId>server-ear</artifactId>
        <type>ear</type>
    </dependency>
</dependencies>

И настал черед плагинов. Для того чтобы скачать и распаковать Wildfly будем использовать maven-dependency-plugin:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
        <execution>
            <id>unpack-wildfly</id>
            <phase>generate-sources</phase>
            <goals>
                <goal>unpack</goal>
            </goals>
            <inherited>false</inherited>
            <configuration>
                <artifactItems>
                    <artifactItem>
                        <groupId>org.wildfly</groupId>
                        <artifactId>wildfly-dist</artifactId>
                        <version>${wildfly.version}</version>
                        <type>zip</type>
                        <overWrite>false</overWrite>
                        <outputDirectory>${project.build.directory}</outputDirectory>
                    </artifactItem>
                </artifactItems>
            </configuration>
        </execution>
    </executions>
</plugin>

Тут все просто, на фазе generate-source у плагина вызываем цель unpack, а в настройках к нему указываем источник, то есть wildfly с версией, которые мы прописали выше. При первом запуске плагин полностью скачает архив с сервером (примерно 140 Мб), однако при последующих запусках он лишь будет его распаковывать, так как файл будет сохранен в каталоге maven.

Возможно пригодится. В данной статье нам это не понадобиться, но часто бывает, что на сервере лежат различные файлы настроек и другие файлы необходимые для работы приложения. Для того чтобы использовать их в тестах пригодится maven-resourse-plugin. То есть, создаем некоторую директорию в нашем модуле для тестов, куда кладем необходимые файлы, а плагин скопирует их, после распаковки сервера. Примерная его настройка ниже:

<plugin>
    <artifactId>maven-resources-plugin</artifactId>
    <version>3.0.1</version>
    <executions>
        <execution>
            <id>copy-resources</id>
            <phase>generate-test-sources</phase>
            <goals>
                <goal>copy-resources</goal>
            </goals>
            <configuration>
                <outputDirectory>${basedir}/target/wildfly-${wildfly.version}/standalone/configuration</outputDirectory>
                <resources>
                    <resource>
                        <directory>${basedir}/config/</directory>
                        <filtering>true</filtering>
                    </resource>
                </resources>
            </configuration>
        </execution>
    </executions>
</plugin>

Для того чтобы управлять сервером довольно часто применяют cargo-plugin, который содержит контейнеры под большинство известных серверов. Настроить данный плагин достаточно непросто, но в нашем случае нам везет, так как у Wildfly есть собственный плагин wildfly-maven-plugin, который довольно прост в настройке. Настроим его:

<plugin>
    <groupId>org.wildfly.plugins</groupId>
    <artifactId>wildfly-maven-plugin</artifactId>
    <version>1.1.0.Alpha8</version>

    <configuration>
        <jboss-home>${project.build.directory}/wildfly-${wildfly.version}</jboss-home>
        <hostname>127.0.0.1</hostname>
        <port>9990</port>
    </configuration>

Если не указывать параметр jboss-home, который указывает где лежит сервер распакованный предыдущим плагином, то wildfly-maven-plugin сам скачает и распакует сервер. Однако, я не нашел возможности контролировать версию, которую он скачивает. По умолчанию он тянет последнюю, но так как на номер версии у нас завязаны, например, некоторые пути, то мы должны быть уверены, что версия wildfly одним прекрасным днем не изменится. Теперь прописываем для плагина необходимые цели:

<executions>
        <execution>
            <id>start-wildfly</id>
            <phase>pre-integration-test</phase>
            <goals>
                <goal>start</goal>
            </goals>
        </execution>

        <execution>
            <id>deploy-server</id>
            <phase>pre-integration-test</phase>
            <goals>
                <goal>deploy-artifact</goal>
            </goals>
            <configuration>
                <groupId>${project.groupId}</groupId>
                <artifactId>server-ear</artifactId>
            </configuration>
        </execution>

        <execution>
            <id>undeploy-app</id>
            <phase>post-integration-test</phase>
            <goals>
                <goal>undeploy</goal>
                <goal>shutdown</goal>
            </goals>
            <configuration>
                <ignoreMissingDeployment>true</ignoreMissingDeployment>
            </configuration>
        </execution>
    </executions>
</plugin>

Итак, по порядку: на фазе pre-integration-test мы стартуем wildfly (также у плагина есть цель run, более подробно про отличие ее от start, и другие цели у плагина можно прочитать в официальной документации), а затем деплоим наш сервер. Ну и после ИТ, то есть на фазе post-integration-test, раздеплоим его и выключаем wildfly. Пока этого будет достаточно. Теперь запустим всю эту писанину, в командной строке переходим в корень проекта и вызываем maven verify -Pit. Параметр -P как раз задает необходимый профиль. Если все успешно, то в логах вы будете наблюдать скачивание wildfly, затем его распаковку, затем старт, деплой сервера и сообщение о регистрации контекста и наконец остановку сервера.

Полный текст файла pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>demoit</artifactId>
        <groupId>ru.alexkulikov</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>itmodule</artifactId>

    <properties>
        <wildfly.version>10.0.0.Final</wildfly.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>${project.parent.groupId}</groupId>
            <version>${project.parent.version}</version>
            <artifactId>server-ear</artifactId>
            <type>ear</type>
        </dependency>
    </dependencies>

    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <execution>
                        <id>unpack-wildfly</id>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>unpack</goal>
                        </goals>
                        <inherited>false</inherited>
                        <configuration>
                            <artifactItems>
                                <artifactItem>
                                    <groupId>org.wildfly</groupId>
                                    <artifactId>wildfly-dist</artifactId>
                                    <version>${wildfly.version}</version>
                                    <type>zip</type>
                                    <overWrite>false</overWrite>
                                    <outputDirectory>${project.build.directory}</outputDirectory>
                                </artifactItem>
                            </artifactItems>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

            <plugin>
                <groupId>org.wildfly.plugins</groupId>
                <artifactId>wildfly-maven-plugin</artifactId>
                <version>1.1.0.Alpha8</version>

                <configuration>
                    <jboss-home>${project.build.directory}/wildfly-${wildfly.version}</jboss-home>
                    <hostname>127.0.0.1</hostname>
                    <port>9990</port>
                </configuration>

                <executions>
                    <execution>
                        <id>start-wildfly</id>
                        <phase>pre-integration-test</phase>
                        <goals>
                            <goal>start</goal>
                        </goals>
                    </execution>

                    <execution>
                        <id>deploy-server</id>
                        <phase>pre-integration-test</phase>
                        <goals>
                            <goal>deploy-artifact</goal>
                        </goals>
                        <configuration>
                            <groupId>${project.groupId}</groupId>
                            <artifactId>server-ear</artifactId>
                        </configuration>
                    </execution>

                    <execution>
                        <id>undeploy-app</id>
                        <phase>post-integration-test</phase>
                        <goals>
                            <goal>undeploy</goal>
                            <goal>shutdown</goal>
                        </goals>
                        <configuration>
                            <ignoreMissingDeployment>true</ignoreMissingDeployment>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

        </plugins>
    </build>

</project>

Leave a Reply

Your email address will not be published. Required fields are marked *