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>
上面配置了两个插件。让我们看看每个插件都做了什么。
build-helper-maven-plugin
正在预留一个临时随机TCP端口,该端口将被MySQL服务器使用。我们不希望在其默认的3306端口上启动服务器,因为那里可能已经有另一个正在运行的服务器。除此之外,如果我们使用一个硬编码的TCP端口,我们将无法并行运行多个构建。在本地开发时可能不是个大问题,但在持续集成环境中可能会有问题。这就是为什么我们首先要预留一个TCP端口。maven-dependency-plugin
正在下载一个 MySQL 分发的 zip 压缩包(一个相当大的文件,对于 Linux 而言超过 300Mb),然后解压它。该压缩包包含与传统的 MySQL 安装所需的完全相同的文件。当解压缩完成后,它就可以作为一个普通的 MySQL 服务器开始提供 SQL 请求的服务了。jcabi-mysql-maven-plugin
启动一个服务器,将其绑定到一个随机保留的TCP端口。我的Maven插件的主要职责是确保MySQL服务器在每个平台(Mac OS,Linux,Windows)上正确启动,并在不再需要时停止。其余的工作由MySQL分发自身完成。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,只需在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