【问题标题】:Starting an H2 Database Server from Maven?从 Maven 启动 H2 数据库服务器?
【发布时间】:2011-01-13 09:22:30
【问题描述】:

假设我想为我的集成测试创建和使用 H2 数据库。

Maven 有一个运行测试的命令:mvn test

有没有办法告诉 maven 为测试启动 H2 数据库服务器并在完成后停止它?

我想这类似于我通过 Maven 命令 (mvn tomcat:run) 运行 tomcat 的方式。

对不起,如果这个问题是荒谬的,我仍在思考新概念。

【问题讨论】:

  • 另外...我看到 H2 可以嵌入到代码中。如果有一种方法可以完全从单元测试或花哨的弹簧配置开始,那在我的书中值得一个“正确答案”!

标签: maven testing h2


【解决方案1】:

我能够在不使用外部服务器的情况下使其工作,只需通过 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>

再一次,这需要我使用基于文件的数据库而不是内存中的数据库。但它确实有效。

【讨论】:

    【解决方案2】:

    您可以使用启动和停止数据库的主要方法创建 2 个小类。这个想法是在运行集成测试之前运行 StartServer 类,然后在运行测试之后运行 StopServer 类。

    您应该按照this document 中某处所述对您的数据库服务器执行相同的操作(描述用于在集成测试中启动和停止 Jetty)

    在您的 pom.xml 中,您应该定义 maven-exec-plugin 以运行 exec:java 目标并创建 2 个执行(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>
    

    希望这就是你想要的

    【讨论】:

    • 我没有使用执行插件(最后,在我做了一些测试之后),我只是创建了一个抽象类,其方法用 BeforeClass 和 AfterClass 注释。这些将执行必要的启动/停止程序。然后为需要数据库的测试类扩展这个类。
    【解决方案3】:

    这个插件可以很好地在集成测试之前使用 tcp 模式生成一个新的 H2 DB(默认插件阶段):h2-maven-plugin on github

    没有很好的文档记录,但您可以查看 Mojo 源以了解配置选项。它发布在 maven Central 上。


    基本上,对于集成测试,您可能希望 Maven:

    • 为您的 Tomcat 服务器和 H2 预留随机可用的网络端口(以避免端口冲突)
    • 启动 H2 服务器
    • 启动 Tomcat 服务器
    • 运行集成测试
    • 停止 Tomcat 服务器
    • 停止 H2 服务器

    这可以通过如下所示的 Maven 配置来实现。 假设您的集成测试使用自定义接口 JUnit 类别进行注释:

    @Category(IntegrationTest.class)
    

    这个 Maven 配置对我来说很好用:

    <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 上下文文件上使用 maven 过滤器,以便替换端口:

       <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 声明的数据源,使用相同的属性...


    如果您希望能够设置集成测试 tomcat 并从您的 IDE 运行集成测试,则需要额外的一趟:

    您可以使用属性来分叉或不分叉 Tomcat 服务器:

    <fork>${integrationTestsForkTomcatJvm}</fork>
    

    当你设置 fork=false 时,服务器会阻塞,maven 不会继续,所以集成测试不会运行,但是你可以从你的 ide 运行它们。

    【讨论】:

      【解决方案4】:

      我在运行单元测试之前创建了一个基于文件的 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 创建数据库。运行测试时,请确保通过休眠属性连接到 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。

      【讨论】:

      • 我很惊讶当我找到这个答案时,2 年内都没有投票。它实际上并没有回答如何启动数据库服务器的问题,而是以更好的方式解决了它;不要启动服务器在磁盘上创建数据库状态,然后将数据库嵌入到正在测试的进程中。这将更快,更可靠(找到要运行的端口没有问题),并且适合大多数情况下测试使用数据库的单个进程。所以这是一个很好的解决方案。谢谢!
      【解决方案5】:

      在我的项目中,为了进行单元测试,我让 Spring 来处理这个数据库的创建和初始化。如H2 documentation 中所述,您可以为此创建一个 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>
      

      您只需在开始单元测试时使用此配置启动 Spring 上下文。

      【讨论】:

        【解决方案6】:

        我刚刚为 maven @ bitbucket 启动了 H2 插件项目。如有任何帮助,我将不胜感激。

        https://bitbucket.org/dohque/maven-h2-plugin

        希望对您有所帮助。

        【讨论】:

          【解决方案7】:

          如果你想在内存中创建它,那么只需使用不同的 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

          【讨论】:

            【解决方案8】:

            以下为我完成了这项工作(仅使用 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 不是项目依赖项。 如果您拥有它,您可能不需要将其显式命名为插件依赖项。

            【讨论】:

              【解决方案9】:

              由于 H2 不提供 Maven 插件,您应该使用 maven-antrun-plugin 启动它。在 ant 任务中编写启动和停止 h2 引擎的代码,并在您的集成测试启动和停止时调用它。

              查看http://docs.codehaus.org/display/MAVENUSER/Maven+and+Integration+Testing的详细信息

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2010-12-02
                • 2017-09-11
                • 2022-01-06
                • 1970-01-01
                • 2023-03-19
                • 2019-09-13
                • 2021-11-06
                • 1970-01-01
                相关资源
                最近更新 更多