JUnit 测试:为什么 Maven (Surefire) 在 Eclipse 上比 运行 慢这么多?

JUnit Tests: Why is Maven (Surefire) so much slower than running on Eclipse?

我正在开发一个相当大的应用程序,其中包含约 260k LOC 和大约 1800 个单元测试。一点背景:

  1. 多模块 Maven 项目
  2. 所有测试 运行 在单独的模块上进行,JaCoCo 用于检查覆盖率。
  3. 测试放在一些套件中,然后套件包含在 Surefire 的配置中。
  4. 使用 SpringJUnit4ClassRunner 进行 运行 测试
  5. Surefire 当前配置为使用相同的 VM 进行构建和测试(forkCount 等于 1,reuseForks 等于 true)。这样做我确定我正在使用 Spring 的静态上下文缓存的优势(在每个测试中重复使用相同的 ApplicationContext

当我们运行 在我们的开发 VM 上测试时,使用 Oracle JDK 7u79/80 我们看到测试速度非常快。例如,具有 50 多种测试方法的相当大的测试 class 大约需要 1:30m(包括上下文初始化时间)到 运行。

我们的基本 Dev VM 是这样的:

我们使用 Jenkins 作为 CI 服务器,Maven (3.2) 负责构建过程。我们有一个 Master + 2 Slaves 架构。所有虚拟机都完全相同:

还记得那些在我们的 Eclipse 上通常需要 1:30 分钟到 运行 分钟的测试吗?在服务器上,他们需要超过 15 分钟才能 运行!这是我已经尝试过的(到目前为止没有成功。):

最重要的是,Surefire 的执行速度比 运行ing JUnit 在 Eclipse 上慢得多有什么具体原因吗?这几天我一直在摸不着头脑,这真的开始让我烦恼了!当解决方案看起来如此接近但它是如此遥远时,我讨厌它。

我无法在我的 Dev 机器上使用 Maven 进行测试,因为我无法分配执行此操作所需的所有内存,但是 运行ning 块 classes(不是整个 1.8 k 测试套件)仍然显示比 Eclipse 上的 运行ning 慢得多。

我知道 Maven 有所有这些阶段等等,但差异应该不会这么大。你不同意吗?

任何输入将不胜感激。我可以提供您认为需要的任何更多信息!

PS: Surefire v2.17, Maven 3.2.2, JUnit 4.12, Spring 测试 3.2.13

非常感谢!

更新 1

我尝试在 CI 服务器上停用 JaCoCo 以查看它是否影响构建时间。它没有。执行时间保持不变。

您可以尝试通过 运行 mvn test 在本地重现远程 surefire 运行。关于分叉,你确定你 运行 是相同的设置吗?

我知道 surefire 的 fork 设置非常复杂,并且随着时间的推移发生了一些变化(详细说明请参见此处:https://maven.apache.org/surefire/maven-surefire-plugin/examples/fork-options-and-parallel-execution.html)。

如果测试每次都分叉并且不重复使用分叉,则 SpringTestRunner 可能会花费很长时间来一次又一次地初始化应用程序。

您确定真正减慢速度的是 surefire 测试吗?

我在这方面取得了一些进展。正如我上面所说,这是一个多模块(20+)Maven 应用程序。我们将所有测试分开放在一个模块上,但 Surefire 的配置是在父 POM 上完成的,而不是在测试模块的 POM 上完成的。

在尝试了所有方法之后,我们决定将测试执行配置单独引入此模块,跳过所有其他模块。这使套件执行从 ~45' 到 22'。我们正在为此绞尽脑汁,一旦我们了解发生了什么,我将再次post。

TL;DR: This image explains everything. (off-topic, safe for work)

感谢您的参与!

我知道这是一个旧线程,但也许它仍然很有趣:如果您的工作负载使用大量 stdout 或 stderr,surefire 将创建三倍于您的输出的大数组,以便将未转义的输出保存到其中.这导致 surefire 比在 eclipse 或 gradle.

中执行相同的测试花费更多的时间

我创建了一个分支 https://github.com/DaGeRe/maven-surefire 并将查看是否可以将其合并到 surefire 中。我的个人测试从 ~1100 ms 到 ~370ms 使用补丁插件。