Maven:在运行单元测试时忽略模块间的依赖关系

cho*_*ver 5 unit-testing build maven multi-module jenkins

我们有一个大型的多模块 Maven 项目。我一直在尝试使用 -T 选项加速我们的单元测试构建,并取得了一些积极的结果。但是,我们的项目中有一些依赖路径是这样的:

模块 A <- 模块 B <- 模块 C

每个模块的单元测试需要 20-30 分钟。由于 -T 选项按其相关顺序构建模块,因此总构建时间为 90 分钟。如果我可以先编译所有模块,然后并行运行 A、B 和 C 的测试,那真的会加快构建速度。例如。像这样的东西:

$ mvn -T 10 clean install -DskipTests
$ mvn -T 10 --ignore-dependencies test
Run Code Online (Sandbox Code Playgroud)

问题:Maven 是否支持开箱即用?

我一直在考虑编写一个小脚本的想法,该脚本将解析 mvn dependency:tree 的输出并并行调用“mvn test -pl A”、“mvn test -pl B”等,但显然如果 Maven有一个开箱即用的解决方案,这将是更可取的。

我们正在使用 Jenkins,所以如果有一些 Jenkins 插件或我错过的 Jenkins 功能支持这一点,那会很有帮助!

注意:加速 A、B 和 C 的单元测试将需要大量工作,并且不能保证单个模块中的测试是可并行的

A_D*_*teo 2

一个可能的解决方案如下:

  • 创建一个附加模块,例如testsuite-module
  • 添加到testsuite-module所有其他模块作为test范围内的依赖项
  • 通过Build Helper Maven Plugin添加到testsuite-module其他模块的所有测试源及其目标add-test-source
  • 仅在此模块上执行作业的第二步并并行运行测试

例如,POM 文件可能testsuite-module如下所示:

<project>
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.sample</groupId>
        <artifactId>modules</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <artifactId>testsuite-module</artifactId>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>build-helper-maven-plugin</artifactId>
                <version>1.10</version>
                <executions>
                    <execution>
                        <id>add-test-source</id>
                        <phase>generate-test-sources</phase>
                        <goals>
                            <goal>add-test-source</goal>
                        </goals>
                        <configuration>
                            <sources>
                                <source>../module-a/src/test</source>
                                <source>../module-b/src/test</source>
                            </sources>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>com.sample</groupId>
            <artifactId>module-a</artifactId>
            <version>0.0.1-SNAPSHOT</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.sample</groupId>
            <artifactId>module-b</artifactId>
            <version>0.0.1-SNAPSHOT</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>
Run Code Online (Sandbox Code Playgroud)

它的唯一范围是收集其他模块的所有源测试,在测试范围/类路径中包含所需的模块并通过例如以下方式执行它们:

mvn -pl testsuite-module test -T 10
Run Code Online (Sandbox Code Playgroud)

这将在一次测试执行中执行所有测试,因此可能满足您的要求。

关于这种方法的几点考虑:

  • testsuite-module对您的项目无害,如果需要(和推荐),您也可以将其移动到 CI 配置文件,如这篇 SO 帖子中所述
  • 您可以考虑也使用add-test-resourceBuild Helper 插件的目标
  • 您可能在测试名称(不同模块中具有相同名称的两个测试用例)或测试资源上存在冲突,这可能是一个更大的问题,但不应该不可能解决
  • 如果依赖模块的测试首先失败,您可能会浪费时间(并且会适得其反),但是您的要求已经预见到了这一点(我认为是假设)