1. 概述

在典型的测试驱动开发中,我们的目标是编写大量能够快速运行和独立设置的低级单元测试。此外,也很少有依赖于外部系统的高级集成测试,例如设置服务器或数据库。毫不奇怪,这些通常既耗费资源又耗费时间。

因此,这些 测试主要需要一些集成前设置和集成后清理才能正常终止。 因此,最好区分这两种类型的测试,并能够在构建过程中单独运行它们。

在本教程中,我们将比较最常用于在典型Apache Maven构建中运行各种类型测试的 Surefire 和 Failsafe 插件。

2.Surefire插件

Surefire Plugin属于一组 Maven核心插件,用于运行应用程序的单元测试。

项目POM默认包含这个插件,但我们也可以显式配置它:

<build>
    <pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.0.0-M5</version>
                ....
            </plugin>
         </plugins>
    </pluginManagement>
</build>

该插件绑定到默认生命周期测试 阶段。因此,让我们使用以下命令来执行它:

mvn clean test

这将运行我们项目中的所有单元测试。由于 Surefire 插件与 测试 阶段绑定,如果任何测试失败,构建都会失败,并且在构建过程中不会执行任何其他阶段

或者,我们可以修改插件配置来运行集成测试以及单元测试。然而,对于集成测试来说,这可能不是理想的行为,因为集成测试可能需要在测试之前进行一些环境设置,以及在测试执行之后进行一些清理。

Maven 正是为此目的提供了另一个插件。

3.故障安全插件

故障安全插件旨在运行项目中的集成测试。

3.1.配置

首先,我们在项目 POM 中进行配置:

<plugin>
    <artifactId>maven-failsafe-plugin</artifactId>
    <version>3.1.2</version>
    <executions>
        <execution>
            <goals>
                <goal>integration-test</goal>
                <goal>verify</goal>
            </goals>
            ....
        </execution>
    </executions>
</plugin>

在这里,插件的目标绑定到构建周期的 集成测试验证 阶段,以便执行集成测试。

现在,让我们从命令行执行 验证 阶段:

mvn clean verify

这会运行 所有集成测试,但如果任何测试在 集成测试 阶段失败,插件不会立即使构建失败

相反,Maven 仍然执行 集成后测试 阶段。因此,作为 集成后测试 阶段的一部分,我们仍然可以执行任何清理和环境拆除。构建过程的后续 验证 阶段会报告所有测试失败。

3.2.例子

在我们的示例中,我们将配置 Jetty 服务器在运行集成测试之前启动并在测试执行之后停止。

首先,让我们将 Jetty 插件添加到 POM 中:

<plugin>
    <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-maven-plugin</artifactId>
    <version>9.4.11.v20180605</version>
    ....
    <executions>
        <execution>
            <id>start-jetty</id>
            <phase>pre-integration-test</phase>
            <goals>
                <goal>start</goal>
            </goals>
        </execution>
        <execution>
            <id>stop-jetty</id>
            <phase>post-integration-test</phase>
            <goals>
                <goal>stop</goal>
            </goals>
        </execution>
    </executions>
</plugin>

在这里,我们添加了分别在 集成前测试集成后测试 阶段启动和停止 Jetty 服务器的配置。

现在,让我们再次执行集成测试并查看控制台输出:

....
[INFO] <<< jetty-maven-plugin:9.4.11.v20180605:start (start-jetty) 
  < validate @ maven-integration-test <<<
[INFO] --- jetty-maven-plugin:9.4.11.v20180605:start (start-jetty)
  @ maven-integration-test ---
[INFO] Started ServerConnector@4b9dc62f{HTTP/1.1,[http/1.1]}{0.0.0.0:8999}
[INFO] Started @6794ms
[INFO] Started Jetty Server
[INFO]
[INFO] --- maven-failsafe-plugin:3.1.2:integration-test (default)
  @ maven-integration-test ---
[INFO]
[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running com.baeldung.maven.it.FailsafeBuildPhaseIntegrationTest
[ERROR] Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.024 s
  <<< FAILURE! - in com.baeldung.maven.it.FailsafeBuildPhaseIntegrationTest
[ERROR] com.baeldung.maven.it.FailsafeBuildPhaseIntegrationTest.whenTestExecutes_thenPreAndPostIntegrationBuildPhasesAreExecuted
  Time elapsed: 0.012 s  <<< FAILURE!
org.opentest4j.AssertionFailedError: expected: <true> but was: <false>
    at com.baeldung.maven.it.FailsafeBuildPhaseIntegrationTest
          .whenTestExecutes_thenPreAndPostIntegrationBuildPhasesAreExecuted(FailsafeBuildPhaseIntegrationTest.java:11)
[INFO]
[INFO] Results:
[INFO]
[ERROR] Failures:
[ERROR]   FailsafeBuildPhaseIntegrationTest.whenTestExecutes_thenPreAndPostIntegrationBuildPhasesAreExecuted:11
  expected: <true> but was: <false>
[INFO]
[ERROR] Tests run: 1, Failures: 1, Errors: 0, Skipped: 0
[INFO]
[INFO] --- jetty-maven-plugin:9.4.11.v20180605:stop (stop-jetty)
  @ maven-integration-test ---
[INFO]
[INFO] --- maven-failsafe-plugin:3.1.2:verify (default)
  @ maven-integration-test ---
[INFO] Stopped ServerConnector@4b9dc62f{HTTP/1.1,[http/1.1]}{0.0.0.0:8999}
[INFO] node0 Stopped scavenging
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
....

在这里,根据我们的配置,Jetty 服务器在集成测试执行之前启动。为了演示,我们有一个失败的集成测试,但这不会立即使构建失败。 集成后测试 阶段在测试执行之后执行,服务器在构建失败之前停止。

相反,如果我们使用 Surefire Plugin 来运行这些集成测试,构建将在 集成测试 阶段停止,而不执行任何所需的清理

对不同类型的测试使用不同插件的另一个好处是各种配置之间的分离。这提高了项目构建的可维护性。

4。结论

在本文中,我们比较了 Surefire 和 Failsafe 插件,用于分离和运行不同类型的测试。我们还查看了一个示例,了解了 Failsafe Plugin 如何为运行需要进一步设置和清理的测试提供附加功能。

与往常一样,代码可以在 GitHub 上获取。