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:

我在几个Java Web项目中使用MySQL,并发现没有Maven插件可以帮助我对我的DAOs进行与真实MySQL服务器的测试。有很多机制可以模拟内存和磁盘上的数据库持久层。然而,确保您的类针对与生产环境中相同的数据库进行测试总是很重要的。

我已经创建了自己的Maven插件,jcabi-mysql-maven-plugin,它只做两件事情:在pre-integration-test阶段启动一个MySQL服务器,并在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 压缩包(一个相当大的文件,对于 Linux 而言超过 300Mb),然后解压它。该压缩包包含与传统的 MySQL 安装所需的完全相同的文件。当解压缩完成后,它就可以作为一个普通的 MySQL 服务器开始提供 SQL 请求的服务了。

  3. jcabi-mysql-maven-plugin 启动一个服务器,将其绑定到一个随机保留的TCP端口。我的Maven插件的主要职责是确保MySQL服务器在每个平台(Mac OS,Linux,Windows)上正确启动,并在不再需要时停止。其余的工作由MySQL分发自身完成。

  4. maven-failsafe-pluginintegration-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,只需在src/test/resources目录中创建一个db.properties文件。在该文件中,您可以执行类似以下操作:

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

Maven 在资源复制过程中会用保留的 TCP 端口号替换 ${mysql.port}。这个操作被称为“资源过滤”,你可以在这里阅读相关内容。

基本上就是这样。我在几个项目中使用jcabi-mysql-maven-plugin,它帮助我确保我的代码可以与真实的MySQL服务器正常工作。我还使用Liquibase Maven 插件,以便在空服务器上填充应用程序所需的表。不过,这是下一篇文章的内容了。

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

sixnines availability badge   GitHub stars