MySQL Maven Plugin

The following text is a partial translation of the original English article, performed by ChatGPT (gpt-3.5-turbo) and this Jekyll plugin:

Я использовал MySQL в нескольких веб-проектах на Java и обнаружил, что нет плагина Maven, который поможет мне протестировать мои DAO против реального сервера MySQL. Есть множество механизмов для имитации слоя сохранения данных в базе как в памяти, так и на диске. Однако всегда полезно убедиться, что ваши классы протестированы на базе данных, идентичной той, которую у вас есть в производственной среде.

Я создал свой собственный плагин Maven, jcabi-mysql-maven-plugin, который делает ровно две вещи: запускает сервер MySQL на этапе pre-integration-test и останавливает его на этапе post-integration-test.

Таким образом, вы можете настроить его в pom.xml (см. также полные инструкции по использованию).

<project>
  <build>
    <plugins>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>build-helper-maven-plugin</artifactId>
        <executions>
          <execution>
            <goals>
              <goal>reserve-network-port</goal>
            </goals>
            <configuration>
              <portNames>
                <portName>mysql.port</portName>
              </portNames>
            </configuration>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <artifactId>maven-dependency-plugin</artifactId>
        <executions>
          <execution>
            <goals>
              <goal>unpack</goal>
            </goals>
            <configuration>
              <artifactItems>
                <artifactItem>
                  <groupId>com.jcabi</groupId>
                  <artifactId>mysql-dist</artifactId>
                  <version>5.6.14</version>
                  <classifier>${mysql.classifier}</classifier>
                  <type>zip</type>
                  <overWrite>false</overWrite>
                  <outputDirectory>
                    ${project.build.directory}/mysql-dist
                  </outputDirectory>
                </artifactItem>
              </artifactItems>
            </configuration>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <groupId>com.jcabi</groupId>
        <artifactId>jcabi-mysql-maven-plugin</artifactId>
        <executions>
          <execution>
            <id>mysql-test</id>
            <goals>
              <goal>classify</goal>
              <goal>start</goal>
              <goal>stop</goal>
            </goals>
            <configuration>
              <port>${mysql.port}</port>
              <data>${project.build.directory}/mysql-data</data>
            </configuration>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <artifactId>maven-failsafe-plugin</artifactId>
        <configuration>
          <systemPropertyVariables>
            <mysql.port>${mysql.port}</mysql.port>
          </systemPropertyVariables>
        </configuration>
        <executions>
          <execution>
            <goals>
              <goal>integration-test</goal>
              <goal>verify</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
  [...]
</project>

Выше настроены два плагина. Давайте посмотрим, что делает каждый из них.

  1. build-helper-maven-plugin резервирует временный случайный TCP-порт, который будет использоваться сервером MySQL. Мы не хотим запускать сервер на его стандартном порту 3306, так как там может уже работать другой сервер. Кроме того, если мы используем жестко закодированный TCP-порт, мы не сможем запускать несколько сборок параллельно. Это может быть не так важно, когда вы разрабатываете локально, но в среде непрерывной интеграции это может стать проблемой. Вот почему мы сначала резервируем TCP-порт.

  2. maven-dependency-plugin загружает дистрибутив MySQL в виде zip-архива (довольно большого файла, более 300 МБ для Linux) и распаковывает его. В этом архиве содержатся те же файлы, которые вы бы использовали для традиционной установки MySQL. После распаковки архива он готов начать обслуживать SQL-запросы как обычный сервер MySQL.

  3. jcabi-mysql-maven-plugin запускает сервер, привязывая его к случайно выбранному TCP-порту. Основной функцией моего плагина Maven является гарантирование правильного запуска сервера MySQL на каждой платформе (Mac OS, Linux, Windows) и его остановка, когда он больше не нужен. Все остальное делается самим распространением MySQL.

  4. maven-failsafe-plugin запускает модульные тесты на этапе integration-test. Его основное отличие от maven-surefire-plugin заключается в том, что он не прерывает сборку, когда некоторые тесты завершаются неудачно. Вместо этого он сохраняет все ошибки в дополнительных файлах в директории target и позволяет продолжить сборку. Позже, когда мы вызываем его цель verify, он прерывает сборку, если во время выполнения его цели integration-test возникли какие-либо ошибки.

Чтобы быть точным, это порядок, в котором Maven будет выполнять настроенные цели:

jcabi-mysql-maven-plugin:classify
maven-dependency-plugin:unpack
build-helper-maven-plugin:reserve-network-port
jcabi-mysql-maven-plugin:start
maven-failsafe-plugin:integration-test
jcabi-mysql-maven-plugin:stop
maven-failsafe-plugin:verify

Запустите mvn clean install и посмотрите, как это работает. Если по какой-то причине не работает, не стесняйтесь сообщить о проблеме на GitHub.

Теперь пришло время создать интеграционный тест, который будет подключаться к временному серверу MySQL, создавать там таблицу и вставлять в нее некоторые данные. Это всего лишь пример, чтобы показать, что сервер MySQL работает и способен обрабатывать транзакции (я использую jcabi-jdbc).

public class FooITCase {
  private static final String PORT = System.getProperty("mysql.port");
  @Test
  public void worksWithMysqlServer() {
    Connection conn = DriverManager.getConnection(
      String.format(
        "jdbc:mysql://localhost:%s/root?user=root&password=root",
        FooITCase.PORT
      )
    );
    new JdbcSession(conn)
      .sql("CREATE TABLE foo (id INT PRIMARY KEY)")
      .execute();
  }
}

Если вы используете Hibernate, просто создайте файл db.properties в каталоге src/test/resources. В этом файле вы можете сделать что-то вроде:

hibernate.connection.url=jdbc:mysql://localhost:${mysql.port}/root
hibernate.connection.username=root
hibernate.connection.password=root

Мавен заменит ${mysql.port} на номер зарезервированного TCP-порта во время копирования ресурсов. Эта операция называется “фильтрация ресурсов”, и вы можете прочитать о ней здесь.

Вот и все. Я использую jcabi-mysql-maven-plugin в нескольких проектах, и он помогает мне быть уверенным в том, что мой код работает с настоящим сервером MySQL. Я также использую плагин Liquibase для Maven, чтобы заполнить пустой сервер таблицами, необходимыми для приложения. Тем не менее, это будет рассказано в следующей статье.

Translated by ChatGPT gpt-3.5-turbo/35 on 2023-09-09 at 16:31

sixnines availability badge   GitHub stars