Практическое руководство. Запуск тестов интеграции maven с тестовой средой (базой данных)
Я использую maven и maven-failafe-plugin для запуска причала во время фазы жизненного цикла интеграции-тестирования. Затем я выполняю несколько тестов (* IT.java) junit против моего запуска webapp. Это работает как ожидалось.
Однако я хотел бы подключиться к тестовой базе данных для своих тестов интеграции. Я сохраняю его URL в
${basedir}/src/test/resources/jdbc.properties
Когда плагин причала работает (причал: бег), он использует
${basedir}/src/main/resources/jdbc.propertes
вместо этого. Я попытался переконфигурировать плагин причала с помощью свойства classesDirectory, чтобы использовать
${project.build.testOutputDirectory}
но в каталоге тестовых классов отсутствуют мои фактические скомпилированные классы проектов, а также ресурсы, хранящиеся в
${basedir}/src/main/resources
note: surefire добавляет тестовые ресурсы к пути к классам, за которыми следуют основные ресурсы, так что все, что содержится в обоих, будет использовать тестовую версию, потому что она найдена сначала в пути к классам.
Любые идеи о том, как правильно настроить эту настройку?
Спасибо!
EDIT:
Ну, похоже, что есть свойства конфигурации на плагине приставок, чтобы справиться с этим:
- testClassesDirectory: каталог, содержащий сгенерированные тестовые классы.
- useTestClasspath: если true, то и зависимости теста будут помещены сначала в путь пути выполнения.
К сожалению, они не работают.
Вот соответствующая часть моего 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>
Ответы
Ответ 1
У меня есть одна и та же проблема, и я решил ее использовать с помощью пользовательского 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>
My 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>
Это должно привести вас к правильному пути
Ответ 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>
Я использовал spring config
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/myDS" />
</bean>
Ответ 3
Я попробовал как авторов, так и предложение @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>
Обратите внимание на свойство System, называемое "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>
Ответ 4
Я борюсь с той же проблемой, но я думаю, что причина, по которой useTestClasspath, похоже, не работает, лежит на самом деле в Spring.
Вероятно, у вас есть такая конфигурация, как:
<context:property-placeholder location="classpath*:**/*.properties"/>
Если вы удалите первый *, я думаю, что он работает, потому что с этой конфигурацией он загружает один и тот же файл свойств из разных мест (как основного, так и тестового, если он существует в обоих). Удаление * будет загружать только тестовый. Поэтому измените его на
<context:property-placeholder location="classpath:**/*.properties"/>