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

问题描述 投票:0回答:3

我正在开发一个相当大的应用程序,该套件有约 260k LOC 和大约 1800 个单元测试。一点背景:

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

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

我们的基本开发虚拟机类似于:

  • 双核 i5 处理器(具有超线程,因此有 4 个虚拟线程)
  • 8GB 内存
  • 中档,SATA HDD(5k 或 7k2 RPM)
  • Windows 7 x64 在客户端模式下运行 Oracle JDK(-client)

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

  • 8 个 Xeon E5 核心(真实核心)
  • 8 GB 内存
  • 为虚拟机提供服务的 SSD LUN(平均吞吐量为 1.2GB/s)
  • Debian Linux 8 x64
  • 服务器模式下的 Oracle JDK

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

  • 将 MAVEN_OPTS 设置为固定堆大小(2GB 堆)、大 PermGen 空间、调整 GC 设置、/dev/urandom 作为随机种子
  • 安装了 32 位 JDK 以使用我们在开发机器上使用的相同客户端模式
  • 调整了Surefire的配置以增加内存,调整GC等。(因为我不再使用分叉的VM来运行测试,所以我将其取出,因为它不会改变任何东西。)

底线,是否有任何具体原因可以解释为什么 Surefire 的执行速度比在 Eclipse 上运行 JUnit 慢得多?我已经为此挠头好几天了,这真的开始让我烦恼了!我讨厌当解决方案看起来如此接近但又如此遥远时。

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

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

任何意见都将受到高度赞赏。我可以提供您认为必要的任何更多信息!

PS:Surefire v2.17、Maven 3.2.2、JUnit 4.12、Spring Test 3.2.13

非常感谢!

更新1

我尝试在 CI 服务器上停用 JaCoCo,看看它是否影响构建时间。事实并非如此。执行时间保持不变。

java maven unit-testing junit spring-test
3个回答
3
投票

我知道这是一个旧线程,但也许它仍然很有趣:如果您的工作负载使用大量 stdout 或 stderr,surefire 将创建三倍于您的输出的大数组,以便将未转义的输出保存到其中。这导致 Surefire 比在 Eclipse 或 gradle 中执行相同的测试花费更多的时间。

我创建了一个分支 https://github.com/DaGeRe/maven-surefire 并将看看是否可以将其合并到 Surefire 中。我的个人测试使用修补后的插件从约 1100 毫秒缩短到约 370 毫秒。


2
投票

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

在尝试了一切之后,我们决定将测试执行配置单独引入该模块,跳过所有其他模块。这使得套件的执行时间从约 45 英尺缩短至 22 英尺。我们对此摸不着头脑,一旦我们明白发生了什么,我会再次在这里发帖。

TL;DR:这张图片说明了一切。 (题外话,工作安全)

感谢您的所有意见!


1
投票

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

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

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

您确定是万无一失的测试真正减慢了速度吗?

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.