JUnit 测试:为什么 Maven (Surefire) 在 Eclipse 上比 运行 慢这么多?
JUnit Tests: Why is Maven (Surefire) so much slower than running on Eclipse?
我正在开发一个相当大的应用程序,其中包含约 260k LOC 和大约 1800 个单元测试。一点背景:
- 多模块 Maven 项目
- 所有测试 运行 在单独的模块上进行,JaCoCo 用于检查覆盖率。
- 测试放在一些套件中,然后套件包含在 Surefire 的配置中。
- 使用
SpringJUnit4ClassRunner
进行 运行 测试
- Surefire 当前配置为使用相同的 VM 进行构建和测试(
forkCount
等于 1,reuseForks
等于 true)。这样做我确定我正在使用 Spring 的静态上下文缓存的优势(在每个测试中重复使用相同的 ApplicationContext
)
当我们运行 在我们的开发 VM 上测试时,使用 Oracle JDK 7u79/80 我们看到测试速度非常快。例如,具有 50 多种测试方法的相当大的测试 class 大约需要 1:30m(包括上下文初始化时间)到 运行。
我们的基本 Dev VM 是这样的:
- 双核 i5 处理器(具有超线程,因此有 4 个虚拟线程)
- 8GB 内存
- 中档,SATA HDD(5k 或 7k2 RPM)
- Windows 7 x64 运行ning Oracle JDK 客户端模式 (-client)
我们使用 Jenkins 作为 CI 服务器,Maven (3.2) 负责构建过程。我们有一个 Master + 2 Slaves 架构。所有虚拟机都完全相同:
- 8 个 Xeon E5 内核(真实内核)
- 8 GB 内存
- 为虚拟机提供服务的 SSD LUN(平均吞吐量为 1.2GB/秒)
- Debian Linux 8 x64
- Oracle JDK 服务器模式
还记得那些在我们的 Eclipse 上通常需要 1:30 分钟到 运行 分钟的测试吗?在服务器上,他们需要超过 15 分钟才能 运行!这是我已经尝试过的(到目前为止没有成功。):
- 设置 MAVEN_OPTS 固定堆大小(2GB 堆),大 PermGen space,调整 GC 设置,/dev/urandom 作为随机种子
- 安装了 32 位 JDK 以使用我们在 Dev Machines 上使用的相同客户端模式
- 调整 Surefire 的配置以增加内存、调整 GC 等(因为我不再使用分叉 VM 来 运行 测试,所以我将其取出,因为它不会改变任何东西。)
最重要的是,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 使用补丁插件。
我正在开发一个相当大的应用程序,其中包含约 260k LOC 和大约 1800 个单元测试。一点背景:
- 多模块 Maven 项目
- 所有测试 运行 在单独的模块上进行,JaCoCo 用于检查覆盖率。
- 测试放在一些套件中,然后套件包含在 Surefire 的配置中。
- 使用
SpringJUnit4ClassRunner
进行 运行 测试 - Surefire 当前配置为使用相同的 VM 进行构建和测试(
forkCount
等于 1,reuseForks
等于 true)。这样做我确定我正在使用 Spring 的静态上下文缓存的优势(在每个测试中重复使用相同的ApplicationContext
)
当我们运行 在我们的开发 VM 上测试时,使用 Oracle JDK 7u79/80 我们看到测试速度非常快。例如,具有 50 多种测试方法的相当大的测试 class 大约需要 1:30m(包括上下文初始化时间)到 运行。
我们的基本 Dev VM 是这样的:
- 双核 i5 处理器(具有超线程,因此有 4 个虚拟线程)
- 8GB 内存
- 中档,SATA HDD(5k 或 7k2 RPM)
- Windows 7 x64 运行ning Oracle JDK 客户端模式 (-client)
我们使用 Jenkins 作为 CI 服务器,Maven (3.2) 负责构建过程。我们有一个 Master + 2 Slaves 架构。所有虚拟机都完全相同:
- 8 个 Xeon E5 内核(真实内核)
- 8 GB 内存
- 为虚拟机提供服务的 SSD LUN(平均吞吐量为 1.2GB/秒)
- Debian Linux 8 x64
- Oracle JDK 服务器模式
还记得那些在我们的 Eclipse 上通常需要 1:30 分钟到 运行 分钟的测试吗?在服务器上,他们需要超过 15 分钟才能 运行!这是我已经尝试过的(到目前为止没有成功。):
- 设置 MAVEN_OPTS 固定堆大小(2GB 堆),大 PermGen space,调整 GC 设置,/dev/urandom 作为随机种子
- 安装了 32 位 JDK 以使用我们在 Dev Machines 上使用的相同客户端模式
- 调整 Surefire 的配置以增加内存、调整 GC 等(因为我不再使用分叉 VM 来 运行 测试,所以我将其取出,因为它不会改变任何东西。)
最重要的是,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 使用补丁插件。