从Maven启动H2数据库服务器?
假设我想为我的集成testing创build和使用H2数据库。
Maven有一个运行testing的命令: mvn test
。
有没有办法告诉maven启动H2数据库服务器进行testing,并在完成时停止它?
我想像这个工作类似于我可以通过Maven命令( mvn tomcat:run
) mvn tomcat:run
。
对不起,如果这个问题是荒谬的,我仍然围绕着新的概念。
我可以在不使用外部服务器的情况下正常工作,只需通过Maven添加依赖到H2,然后使用这个bean:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="org.h2.Driver"/> <property name="url" value="jdbc:h2:file:h2\db"/> <property name="username" value="sa"/> <property name="password" value=""/> </bean>
然后再次,这需要我使用基于文件的数据库,而不是在内存中。 但它是诀窍。
您可以使用主要方法创build2个小类,以启动和停止数据库。 这个想法是在运行集成testing之前运行StartServer类,然后在运行testing之后运行类StopServer。
你应该对你的数据库服务器执行相同的操作,如本文档中所描述的那样(描述是为了在集成testing中启动和停止Jetty)
在您的pom.xml中,您应该定义maven-exec-plugin来运行exec:java目标并创build2个执行(1个用于调用StartServer,1个用于StopServer):
<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <version>1.1.1</version> <executions> <execution> <!-- start server before integration tests --> <id>start</id> <phase>pre-integration-test</phase> <goals> <goal>java</goal> </goals> <configuration> <mainClass>com.foo.StartServer</mainClass> </configuration> </execution> <execution> <!-- stop server after integration tests --> <id>stop</id> <phase>post-integration-test</phase> <goals> <goal>java</goal> </goals> <configuration> <mainClass>com.foo.StopServer</mainClass> </configuration> </execution> </executions> </plugin>
希望这就是你想要的
这个插件工作正常,在集成testing(默认插件阶段)之前产生一个新的H2数据库与tcp模式: h2-maven-plugin on github
它没有很好的logging,但你可以检查Mojo的来源知道configuration选项。 它在Maven中心发布。
基本上,对于集成testing,您可能希望Maven:
- 预留随机可用的networking端口,用于Tomcat服务器和H2(避免端口冲突)
- 启动H2服务器
- 启动Tomcat服务器
- 运行集成testing
- 停止Tomcat服务器
- 停止H2服务器
这可以通过一个像这样的Mavenconfiguration来实现。 假设您的集成testing使用自定义接口JUnit类别进行注释:
@Category(IntegrationTest.class)
这个Mavenconfiguration适合我:
<profile> <id>it</id> <build> <plugins> <!-- Reserve randomly available network ports --> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>build-helper-maven-plugin</artifactId> <executions> <execution> <id>reserve-network-port</id> <goals> <goal>reserve-network-port</goal> </goals> <phase>process-resources</phase> <configuration> <portNames> <portName>tomcat.test.http.port</portName> <portName>h2.test.tcp.port</portName> </portNames> </configuration> </execution> </executions> </plugin> <!-- Start H2 before integration tests, accepting tcp connections on the randomly selected port --> <plugin> <groupId>com.edugility</groupId> <artifactId>h2-maven-plugin</artifactId> <version>1.0</version> <configuration> <port>${h2.test.tcp.port}</port> </configuration> <executions> <execution> <id>Spawn a new H2 TCP server</id> <goals> <goal>spawn</goal> </goals> </execution> <execution> <id>Stop a spawned H2 TCP server</id> <goals> <goal>stop</goal> </goals> </execution> </executions> </plugin> <!-- Start Tomcat before integration tests on the --> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <configuration> <systemProperties> <spring.profiles.active>integration_tests</spring.profiles.active> <httpPort>${http.test.http.port}</httpPort> <h2Port>${h2.test.tcp.port}</h2Port> </systemProperties> <port>${http.test.http.port}</port> <contextFile>src/main/java/META-INF/tomcat/webapp-test-context-using-h2.xml</contextFile> <fork>true</fork> </configuration> <executions> <execution> <id>run-tomcat</id> <phase>pre-integration-test</phase> <goals> <goal>run</goal> </goals> </execution> <execution> <id>stop-tomcat</id> <phase>post-integration-test</phase> <goals> <goal>shutdown</goal> </goals> </execution> </executions> <dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <version>${h2.version}</version> </dependency> </dependencies> </plugin> <!-- Run the integration tests annotated with @Category(IntegrationTest.class) --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-failsafe-plugin</artifactId> <!-- Bug in 2.12.x --> <version>2.11</version> <dependencies> <dependency> <groupId>org.apache.maven.surefire</groupId> <artifactId>surefire-junit47</artifactId> <version>2.12.4</version> </dependency> </dependencies> <configuration> <groups>com.mycompany.junit.IntegrationTest</groups> <failIfNoTests>false</failIfNoTests> <junitArtifactName>junit:junit-dep</junitArtifactName> <systemPropertyVariables> <httpPort>${tomcat.test.http.port}</httpPort> <h2Port>${h2.test.tcp.port}</h2Port> </systemPropertyVariables> </configuration> <executions> <execution> <goals> <goal>integration-test</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </profile>
您可能希望在tomcat上下文文件上使用mavenfilter,以便replace端口:
<contextFile>src/main/java/META-INF/tomcat/webapp-test-context-using-h2.xml</contextFile>
随着文件内容是:
<Resource name="jdbc/dataSource" auth="Container" type="javax.sql.DataSource" maxActive="100" maxIdle="30" maxWait="10000" username="" password="" driverClassName="org.h2.Driver" url="jdbc:h2:tcp://localhost:${h2.test.tcp.port}/mem:db;DB_CLOSE_ON_EXIT=FALSE;MODE=MySQL"/>
或者如果你不想要一个JNDI数据源,你可以使用Spring声明的dataSource,使用相同的属性…
如果您希望能够设置您的集成testingtomcat,并且从您的IDE运行集成testing:
你可以使用一个属性来fork或不Tomcat服务器:
<fork>${integrationTestsForkTomcatJvm}</fork>
当你设置fork = false时,服务器将被阻塞,maven将不会继续运行,所以集成testing将不会运行,但是你可以从ide运行它们。
在我的项目中,对于unit testing,我要求Spring处理这个数据库的创build和初始化。 正如在H2文档中所述,您可以为此创build一个bean:
<bean id = "org.h2.tools.Server" class="org.h2.tools.Server" factory-method="createTcpServer" init-method="start" destroy-method="stop"> <constructor-arg value="-tcp,-tcpAllowOthers,true,-tcpPort,8043" /> </bean>
当你开始你的unit testing时,你只需要用这个configuration来启动Spring上下文。
我在unit testing运行之前创build一个基于文件的H2数据库。 该文件位于target
目录中,可以随时使用mvn clean
进行删除。
我使用maven-sql-plugin如下:
<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>sql-maven-plugin</artifactId> <version>1.5</version> <dependencies> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <version>1.3.166</version> </dependency> </dependencies> <configuration> <driver>org.h2.Driver</driver> <url>jdbc:h2:file:target/db/testdb</url> <username>sa</username> <password></password> <autocommit>true</autocommit> <skip>${maven.test.skip}</skip> </configuration> <executions> <execution> <id>create-db</id> <phase>process-test-resources</phase> <goals> <goal>execute</goal> </goals> <configuration> <srcFiles> <srcFile>${sql.dir}/drop_db.sql</srcFile> <srcFile>${sql.dir}/tables.sql</srcFile> <srcFile>${sql.dir}/constraints.sql</srcFile> ... etc ... </srcFiles> </configuration> </execution> </executions> </plugin>
数据库可以通过运行mvn process-test-resources
来创build。 运行testing时,确保通过hibernate属性连接到target/db/testdb
的数据库。
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" p:driverClassName="org.h2.Driver" p:url="jdbc:h2:file:target/db/testdb" p:username="sa" p:password="" />
您还需要依赖maven的依赖项中的com.h2database.h2。
如果你想在内存中,那么只需使用不同的URL:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="org.h2.Driver"/> <property name="url" value="jdbc:h2:mem:db"/> <property name="username" value="sa"/> <property name="password" value=""/> </bean>
您可以提供其他选项,例如:; DB_CLOSE_DELAY = -1
请参阅: http : //www.h2database.com/html/features.html#in_memory_databases
由于H2不提供Maven插件,所以你应该使用maven-antrun-plugin来启动它。 在ant任务中编写启动和停止h2引擎的代码,并在集成testing开始和停止时调用它。
详见http://docs.codehaus.org/display/MAVENUSER/Maven+and+Integration+Testing
下面是我的工作(只使用h2
依赖和exec-maven-plugin
):
<build> <plugins> <!-- start/stop H2 DB as a server --> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <version>1.2.1</version> <executions> <execution> <id>start-h2</id> <phase>pre-integration-test</phase> <goals> <goal>java</goal> </goals> <configuration> <mainClass>org.h2.tools.Server</mainClass> <arguments> <argument>-tcp</argument> <argument>-tcpDaemon</argument> </arguments> </configuration> </execution> <execution> <id>stop-h2</id> <phase>post-integration-test</phase> <goals> <goal>java</goal> </goals> <configuration> <mainClass>org.h2.tools.Server</mainClass> <arguments> <argument>-tcpShutdown</argument> <argument>tcp://localhost:9092</argument> </arguments> </configuration> </execution> </executions> <configuration> <includeProjectDependencies>true</includeProjectDependencies> <includePluginDependencies>true</includePluginDependencies> <executableDependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> </executableDependency> </configuration> <dependencies> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <version>1.3.173</version> </dependency> </dependencies> </plugin> </plugins> </build>
请注意,在我的pom.xml
, com.h2database:h2
不是项目依赖项。 如果你有它,你可能不需要明确地将其命名为插件依赖项。