如何:针对测试环境(数据库)运行 Maven 集成测试
Posted
技术标签:
【中文标题】如何:针对测试环境(数据库)运行 Maven 集成测试【英文标题】:How to: Run maven integration tests against a test environment (database) 【发布时间】:2011-06-29 22:33:39 【问题描述】:我正在使用 maven 和 maven-failsafe-plugin 在集成测试生命周期阶段启动码头。然后,我对正在运行的 webapp 执行一些 (*IT.java) junit 测试。这按预期工作。
但是,我想为我的集成测试连接到一个测试数据库。我将其网址存储在
$basedir/src/test/resources/jdbc.properties
jetty 插件运行时(jetty:run),它使用
$basedir/src/main/resources/jdbc.propertes
相反。我尝试通过 classesDirectory 属性重新配置码头插件以使用
$project.build.testOutputDirectory
但 test-classes 目录缺少我实际编译的项目类,以及存储在其中的资源
$basedir/src/main/resources
注意:surefire 将测试资源添加到类路径,然后是主要资源,这样在两者中找到的任何内容都将使用测试版本,因为它首先在类路径中找到。
关于如何正确设置的任何想法?
谢谢!
编辑:
好吧,码头插件上似乎有configuration properties来处理这个问题:
testClassesDirectory : 包含生成的测试类的目录。 useTestClasspath : 如果为 true,则 test 的和依赖项将首先放在运行时类路径中。不幸的是,它们不起作用。
这是我的 pom.xml 的相关部分:
<testResources> <testResource> <filtering>true</filtering> <directory>src/test/resources</directory> </testResource> </testResources> <plugins> <plugin> <groupId>org.mortbay.jetty</groupId> <artifactId>maven-jetty-plugin</artifactId> <version>6.1.26</version> <configuration> <contextPath>/</contextPath> <stopPort>8005</stopPort> <stopKey>STOP</stopKey> </configuration> <executions> <execution> <id>start-jetty</id> <phase>pre-integration-test</phase> <goals> <goal>run</goal> </goals> <configuration> <daemon>true</daemon> <useTestClasspath>true</useTestClasspath> <testClassesDirectory>$project.build.testOutputDirectory</testClassesDirectory> </configuration> </execution> <execution> <id>stop-jetty</id> <phase>post-integration-test</phase> <goals> <goal>stop</goal> </goals> </execution> </executions> </plugin> <plugin> <artifactId>maven-failsafe-plugin</artifactId> <version>2.6</version> <executions> <execution> <goals> <goal>integration-test</goal> <goal>verify</goal> </goals> </execution> </executions> <configuration> <useFile>false</useFile> </configuration> </plugin>
【问题讨论】:
你能添加你的POM的相关部分吗? 谢谢,这对我帮助很大。需要注意的一件事是,我试图使用 run-exploded 目标(根据故障安全文档),它不支持 useTestClassPath 或 testClassesDirectory。 【参考方案1】:我尝试了作者和@thehpi 的建议。两者都是可信的,但是当我尝试它们时遇到了一些问题。我的设置如下,maven 项目,使用带有 maven-failsafe-plugin
的集成测试,使用 JPA 和用于告诉容器如何连接到数据库的 persistence.xml 文件。
长话短说,下面详细介绍的是如何使用 JVM 属性来告诉您的真实代码只需使用不同的persistence-unit
。其他解决方案让我在使用 Hibernate 4.1 和 Jetty 7 时遇到了麻烦(查找数据源的问题)。
唯一的缺点是您最终会在项目的发布版本中得到一个无用的配置。辅助持久性单元永远不会在 Maven 集成测试之外使用。我确信有一种方法可以将它分开,但对我来说,我可以接受这种方法。我什至将 hsqldb.jar 从构建中拉出,并使其成为仅用于插件执行的依赖项。
来自 POM 的相关
<plugin>
<inherited>true</inherited>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.8.1</version>
</plugin>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>7.2.0.v20101020</version>
<dependencies>
<dependency>
<groupId>hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>1.8.0.10</version>
</dependency>
</dependencies>
<configuration>
<scanIntervalSeconds>10</scanIntervalSeconds>
<stopPort>8005</stopPort>
<stopKey>STOP</stopKey>
<contextPath>/</contextPath>
</configuration>
<executions>
<execution>
<id>start-jetty</id>
<phase>pre-integration-test</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<scanIntervalSeconds>0</scanIntervalSeconds>
<daemon>true</daemon>
<systemProperties>
<systemProperty>
<name>RUNNING_TESTS</name>
<value>true</value>
</systemProperty>
</systemProperties>
</configuration>
</execution>
<execution>
<id>stop-jetty</id>
<phase>post-integration-test</phase>
<goals>
<goal>stop</goal>
</goals>
</execution>
</executions>
</plugin>
注意名为“RUNNING_TESTS”的系统属性。
HibernateUtil.java
public class HibernateUtil
private static final EntityManagerFactory emfInstance;
static
String istest = System.getProperty("RUNNING_TESTS");
System.out.println("RUNNING_TESTS: " + istest);
if (istest != null && istest.equalsIgnoreCase("true"))
emfInstance = Persistence.createEntityManagerFactory("integration-tests");
else
emfInstance = Persistence.createEntityManagerFactory("productionname");
public static EntityManagerFactory getInstance()
return emfInstance;
private HibernateUtil()
persistence.xml (在 /src/main/resources/META-INF)
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
version="1.0">
<!-- persistence.xml -->
<persistence-unit name="productionname">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<non-jta-data-source>java:comp/env/jdbc/selectivemailpush</non-jta-data-source>
<properties>
<property name="hibernate.archive.autodetection" value="class, hbm" />
<property name="hibernate.dialect" value="org.hibernate.dialect.mysqlDialect" />
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver" />
</properties>
</persistence-unit>
<persistence-unit name="integration-tests">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>...</class>
<class>...</class>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect" />
<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver" />
<property name="hibernate.connection.username" value="sa" />
<property name="hibernate.connection.password" value="" />
<property name="hibernate.connection.url" value="jdbc:hsqldb:mem:integration-tests" />
<property name="hibernate.showSql" value="true" />
<property name="hibernate.format_sql" value="true" />
</properties>
</persistence-unit>
</persistence>
【讨论】:
【参考方案2】:我用过
<configuration>
<jettyEnvXml>src/test/webapp/WEB-INF/jetty-env.xml</jettyEnvXml>
.
.
内容
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
<Configure class="org.mortbay.jetty.webapp.WebAppContext">
<New id="MyDb" class="org.mortbay.jetty.plus.naming.Resource">
<Arg>jdbc/myDS</Arg>
<Arg>
<New class="org.apache.commons.dbcp.BasicDataSource">
<Set name="driverClassName">org.h2.Driver</Set>
<Set name="url">jdbc:h2:mem:testdb;INIT=CREATE SCHEMA IF NOT EXISTS TESTDB\;SET SCHEMA TESTDB</Set>
<Set name="username">sa</Set>
<Set name="password"></Set>
</New>
</Arg>
</New>
</Configure>
我的 web.xml 中也需要
<resource-ref>
<res-ref-name>jdbc/myDS</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>
我使用了弹簧配置
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/myDS" />
</bean>
【讨论】:
【参考方案3】:我正在努力解决同样的问题,但我认为 useTestClasspath 似乎不起作用的原因实际上在于 Spring。
您可能有如下配置:
<context:property-placeholder location="classpath*:**/*.properties"/>
如果您删除第一个 * 我认为它可以工作,因为使用此配置它会从不同位置加载相同的属性文件(主文件和测试文件是否存在于两者中)。删除 * 只会加载测试之一。所以改成
<context:property-placeholder location="classpath:**/*.properties"/>
【讨论】:
【参考方案4】:我有同样的问题,并通过使用自定义 web.xml (jettyweb.xml) 解决了这个问题,请参阅 maven 配置
<build>
<plugins>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<configuration>
<overrideWebXml>./src/main/webapp/WEB-INF/jettyweb.xml</overrideWebXml>
<scanintervalseconds>3</scanintervalseconds>
</configuration>
<dependencies>
</dependencies>
</plugin>
</plugins>
</build>
在我的例子中,我使用这个配置来使用其他一些 spring 配置来管理事务。但是这种策略也可以用于使用其他属性文件。
我原来的web.xml有这个spring配置
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring-hibernate.xml,
/WEB-INF/spring-services.xml
</param-value>
</context-param>
我的 jettyweb.xml 有这个 spring 配置
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring-hibernate-jetty.xml,
/WEB-INF/spring-services.xml
</param-value>
</context-param>
这应该会让你走上正确的道路
【讨论】:
以上是关于如何:针对测试环境(数据库)运行 Maven 集成测试的主要内容,如果未能解决你的问题,请参考以下文章
在多模块 Maven 项目中构建所有模块后,如何运行集成测试?
如何在 Maven 3 中运行嵌入式 Tomcat 9 以进行集成测试?
Jenkins+maven+jmeter接口可持续集成自动化测试