在Maven构建中并行运行junit测试?


110

我正在使用JUnit 4.4和Maven,并且有大量长时间运行的集成测试。

关于并行化测试套件,有一些解决方案可以让我在单个测试类中并行运行每个测试方法。但是所有这些都要求我以一种或另一种方式更改测试。

我真的认为,在X线程中并行运行X个不同的测试类将是一种更干净的解决方案。我有成百上千的测试,所以我真的不在乎线程测试类。

有什么办法吗?

Answers:


75

使用Maven插件:

<build>
    <plugins>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.7.1</version>
        <configuration>
            <parallel>classes</parallel>
            <threadCount>5</threadCount>
        </configuration>
    </plugin>
    </plugins>
</build>

12
如果您使用的是Junit 4.7或更高版本,那么surefire实际上支持<parallel>。
surefire

42

从junit 4.7开始,现在可以并行运行测试,而无需使用TestNG。实际上从4.6开始就可以实现,但是4.7中进行了许多修复,这使其成为一个可行的选择。您还可以使用spring进行并行测试,您可以在此处阅读有关内容


1
链接页面显示“对于大多数双核解决方案,使用并行线程运行目前从来没有比非线程运行更快”。还是这样吗?
Raedwald

2
我认为,如果您的测试执行任何IO,它们仍然会受益。例如,如果您的单元测试更像是集成测试并且访问了数据库,那么并行运行应该可以加快它们的速度。
戴夫

@Raedwald不要对简短的非io绑定单元测试期望太多,这就是我要说的。新版本的surefire也比帖子中描述的2.5更好/更有效,因此您可能会得到更好的结果。
krosenvold

3
您说有可能,但是可以包含一个说明解释的链接吗?你的第二个环节是“弹簧”,这我没有兴趣的。
科里·肯德尔

@krosenvold链接?我正在努力寻找一个内置的解决方案。
Ilan Biala

10

受JUnit实验性ParallelComputer运行器的启发,我构建了自己的ParallelSuiteParallelParameterized运行器。使用这些运行程序,可以轻松地并行化测试套件和参数化测试。

ParallelSuite.java

public class ParallelSuite extends Suite {

    public ParallelSuite(Class<?> klass, RunnerBuilder builder) throws InitializationError {

        super(klass, builder);

        setScheduler(new RunnerScheduler() {

            private final ExecutorService service = Executors.newFixedThreadPool(4);

            public void schedule(Runnable childStatement) {
                service.submit(childStatement);
            }

            public void finished() {
                try {
                    service.shutdown();
                    service.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
                } catch (InterruptedException e) {
                    e.printStackTrace(System.err);
                }
            }
        });
    }
}

ParallelParameterized.java

public class ParallelParameterized extends Parameterized {

    public ParallelParameterized(Class<?> arg0) throws Throwable {

        super(arg0);

        setScheduler(new RunnerScheduler() {

            private final ExecutorService service = Executors.newFixedThreadPool(8);

            public void schedule(Runnable childStatement) {
                service.submit(childStatement);
            }

            public void finished() {
                try {
                    service.shutdown();
                    service.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
                } catch (InterruptedException e) {
                    e.printStackTrace(System.err);
                }
            }
        });
    }
}

用法很简单。只需将@RunWith批注值更改为这些Parallel *类之一即可。

@RunWith(ParallelSuite.class)
@SuiteClasses({ATest.class, BTest.class, CTest.class})
public class ABCSuite {}

5

tempus-fugit提供了类似的功能,请查看文档以获取详细信息。它依靠JUnit 4.7,您只需将测试标记为@RunWith(ConcurrentTestRunner)

干杯


3

您可以签出开源库-Test Load Balancer。它确实满足您的要求-并行运行不同的测试类。它在ant-junit级别上集成,因此您无论如何都不必更改测试。我是图书馆的作者之一。

另外,考虑不要在线程中运行它们,因为您可能需要一个进程级沙箱。例如,如果您在集成测试中命中数据库,则您不希望一个测试失败,因为另一个测试在另一个线程中添加了一些数据。在大多数情况下,编写测试时并未考虑到这一点。

最后,到目前为止如何解决了这个问题?


2

TestNG可以做到这一点(这是我的第一个反应-然后我看到您已经有很多测试用例)。

对于JUnit,请查看parallel-junit


3
不幸的是,这不是我所问问题的答案。parallel-junit仅在单个测试类中运行。TestNG也只能在单个类中运行,而我的测试不是TestNG测试。
krosenvold

@PlatinumAzure:我更新了链接。我不知道这个项目是如何维护的。最近又提出了另一个问题,以在多台计算机上分发junit测试执行
集邮

2

您可以使用Junit本身提供的ParallelComputer并行运行测试。这是一个小片段,可以帮助您入门。

Class[] cls = { TestCase1.class, TestCase2.class };
Result result = JUnitCore.runClasses(ParallelComputer.classes(), cls);
List<Failure> failures = result.getFailures();

当您需要从代码运行测试时,这将有所帮助,因为它不依赖于Maven或任何其他构建管理工具。

请注意,这将并行运行所有测试用例,如果不同测试用例之间有任何依赖关系,则可能导致误报。无论如何,您不应有相互依存的测试。


0

另一个选择:Punner,一个新的并行junit运行器和maven插件。您无需更改代码,将其复制到pom.xml中:

<!-- Disable default surefire based testing -->
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-surefire-plugin</artifactId>
  <version>2.20</version>
  <configuration>
    <skip>true</skip>
  </configuration>
</plugin>

<plugin>
  <groupId>com.github.marks-yag</groupId>
  <artifactId>punner-maven-plugin</artifactId>
  <version>${version}</version>
  <configuration>
  </configuration>
  <executions>
    <execution>
      <id>test</id>
      <phase>test</phase>
      <goals>
        <goal>test</goal>
      </goals>
    </execution>
  </executions>
</plugin>

Punner可以并行运行测试方法,可以分别保存测试输出并保持干净。

Punner会减少您的mvn控制台输出,如下所示:

[INFO] --- punner-maven-plugin:0.9.13:test (test) @ ipc ---
[INFO] Punner report directory: /Users/guile/workspace/ipc/target/punner-reports
[INFO]
[INFO] com.github.yag.ipc.IPCTest.testConnectionHandler.............. PASSED
[INFO] com.github.yag.ipc.IPCTest.testSequence....................... PASSED
[INFO] com.github.yag.ipc.IPCTest.testPartialContent................. PASSED
[INFO] com.github.yag.ipc.IPCTest.testResponseContent................ PASSED
[INFO] com.github.yag.ipc.IPCTest.testPingPong....................... PASSED
[INFO] com.github.yag.ipc.IPCTest.testServerClose.................... PASSED
[INFO] com.github.yag.ipc.IPCTest.testServerSideHeartbeatTimeout..... PASSED
[INFO] com.github.yag.ipc.IPCTest.testClientSideHeartbeatTimeout..... PASSED
[INFO] com.github.yag.ipc.IPCTest.testClientSideHeartbeat............ PASSED
[INFO] com.github.yag.ipc.IPCTest.testClientReconnect................ PASSED
[INFO]
[INFO] Tests run: 10, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 10.952 sec, Time saved: 25.919 sec.

Punner产生与surefire兼容的输出,您还可以从报告目录获取原始日志数据和降价格式报告:

  ipc git:(develop) ll target/punner-reports
total 104
-rw-r--r--   1 guile  staff    11K Oct 15 23:07 TEST-com.github.yag.ipc.IPCTest.xml
-rw-r--r--   1 guile  staff   298B Oct 15 23:07 com.github.yag.ipc.IPCTest.txt
drwxr-xr-x  12 guile  staff   384B Oct  8 00:50 logs
-rw-r--r--   1 guile  staff    33K Oct 15 23:07 report.md

Punner是我的个人项目,我写了Punner来加快其他一些项目的单元测试阶段,例如IPC框架,细粒度的锁定,日记服务,分布式工作流引擎等。它节省了很多我的等待时间。

punner还不支持某些高级功能。如果您可以尝试并给我一些反馈,我感到非常高兴。


-3

您可以在一分钟内将测试更改为TestNg测试(只需更改导入),TestNG是并行测试中最好的。


-3

您可以尝试使用Gridgain,它可以让您跨计算网格分布测试。


1
我已经尝试了GridGain解决方案,并且遇到了两个主要问题。首先,您必须告诉GridGain从网格任务的类路径中排除GridGain也使用的任何东西,例如Spring和许多Apache Commons东西。其次,网络类加载虽然是一个绝妙的主意,但不适用于想要搜索类路径的库,例如Spring
Graham Lea 2010年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.