1. 概述

在项目生命周期中,集成测试的设置是一个常见需求。本教程将介绍如何使用Maven Cargo插件来实现这一场景。

2. Maven集成测试构建阶段

幸运的是,Maven为这种特定场景提供了内置支持。默认构建生命周期(参见Maven官方文档)中的以下阶段:

  • pre-integration-test: 在执行集成测试之前执行所需操作。这可能包括设置所需的环境。
  • integration-test: 如果需要,处理并部署包到一个可以运行集成测试的环境中。
  • post-integration-test: 在执行完集成测试后执行所需操作。这可能包括清理环境。

3. 设置Cargo插件

让我们逐步了解所需的设置。

3.1. 从Surefire插件排除集成测试

首先,需要配置maven-surefire-plugin,以排除标准构建生命周期中的集成测试:

<plugin>
   <groupId>org.apache.maven.plugins</groupId>
   <artifactId>maven-surefire-plugin</artifactId>
   <version>2.22.2</version>
   <configuration>
      <excludes>
         <exclude>**/*IntegrationTest.java</exclude>
      </excludes>
   </configuration>
</plugin>

测试的排除通过ant风格的路径表达式完成,因此所有集成测试必须遵循此模式,并以IntegrationTest.java结尾。

3.2. 配置Cargo插件

接下来,我们将使用cargo-maven3-plugin,因为Cargo为嵌入式Web服务器提供了顶级的开箱即用支持。当然,如果服务器环境需要特定配置,Cargo也知道如何根据存档包构建服务器并部署到外部服务器。

<plugin>
   <groupId>org.codehaus.cargo</groupId>
   <artifactId>cargo-maven3-plugin</artifactId>
   <version>1.9.9</version>
   <configuration>
      <configuration>
         <properties>
            <cargo.servlet.port>8080</cargo.servlet.port>
         </properties>
      </configuration>
   </configuration>
</plugin>

定义了一个默认的嵌入式Jetty 9 Web服务器,监听8080端口。

在Cargo的新版本(1.1.0及以上)中,cargo:start目标的默认值wait被改为false。这个目标只应用于运行集成测试,并绑定到Maven生命周期;对于开发,应该使用cargo:run目标,其默认值为wait=true

为了让package Maven阶段生成一个可部署的war文件,项目的打包类型必须是<packaging>war</packaging>

3.3. 添加新的Maven配置文件

接下来,创建一个新的集成Maven配置文件,以便仅在激活此配置文件时运行集成测试,而不是作为标准构建生命周期的一部分。

<profiles>
   <profile>
      <id>integration</id>
      <build>

         <plugins>
            ...
         </plugins>

      </build>
   </profile>
</profiles>

这个配置文件将包含剩余的所有配置细节。

现在,Jetty服务器被配置在pre-integration-test阶段启动,在post-integration-test阶段停止。

<plugin>
   <groupId>org.codehaus.cargo</groupId>
   <artifactId>cargo-maven3-plugin</artifactId>
   <executions>
      <execution>
         <id>start-server</id>
         <phase>pre-integration-test</phase>
         <goals>
            <goal>start</goal>
         </goals>
      </execution>
      <execution>
         <id>stop-server</id>
         <phase>post-integration-test</phase>
         <goals>
            <goal>stop</goal>
         </goals>
      </execution>
   </executions>
</plugin>

这确保了cargo:startcargo:stop目标将在integration-test阶段之前和之后执行。请注意,由于有两个独立的执行定义,所以id元素必须在两个地方都存在且不同,以便Maven可以接受配置。

3.4. 在新配置文件中配置集成测试

接下来,需要在integration配置文件中覆盖maven-surefire-plugin的配置,以便将默认生命周期中排除的集成测试包含并运行:

<plugins>
   <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-surefire-plugin</artifactId>
      <executions>
         <execution>
            <phase>integration-test</phase>
            <goals>
               <goal>test</goal>
            </goals>
            <configuration>
               <excludes>
                  <exclude>none</exclude>
               </excludes>
               <includes>
                  <include>**/*IntegrationTest.java</include>
               </includes>
            </configuration>
         </execution>
      </executions>
   </plugin>
</plugins>

有几个值得注意的地方:

  1. maven-surefire-plugintest目标在integration-test阶段执行;此时,Jetty已经启动,项目已部署,因此集成测试应该可以顺利运行。

  2. 集成测试现在被包含在执行中。为了实现这一点,需要重写排除规则——这是由于Maven在配置文件内处理插件配置的方式。

基础配置并没有完全被覆盖,而是在配置文件内部添加了新的配置元素。

正因为如此,原始的<excludes>配置仍然存在于配置文件中,需要被覆盖,否则它会与<includes>配置冲突,测试仍然无法运行。

  1. 注意,由于只有一个<execution>元素,不需要定义id

现在整个过程可以运行:

mvn clean install -Pintegration

4. 总结

逐步配置Maven涵盖了作为项目生命周期一部分设置集成测试的全过程。

通常,这会在持续集成环境中设置,最好在每次提交后进行。如果CI服务器已经有了运行并占用端口的服务器,那么Cargo配置将需要处理这种情况,我将在后续的文章中详细介绍。

要查看完整的配置示例,请参阅REST GitHub项目

此外,还可以阅读这篇文章,了解最佳实践,关于如何组织项目结构和安排单元测试和集成测试。