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

时间:2015-06-10 08:30:10

标签: java maven unit-testing junit spring-test

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

  1. 多模块Maven项目
  2. 所有测试都在一个单独的模块上运行,JaCoCo用于检查覆盖范围。
  3. 测试在一些套件中放在一起,然后套件包含在Surefire的配置中。
  4. 使用SpringJUnit4ClassRunner运行测试
  5. Surefire目前配置为使用相同的VM进行构建和测试(forkCount等于1,reuseForks等于true。这样做我确信我正在使用Spring的静态上下文缓存的优点(在每次测试中重用相同的ApplicationContext
  6. 当我们在开发虚拟机上运行测试时,使用Oracle JDK 7u79 / 80,我们看到了非常快速的测试。例如,具有50多种测试方法的相当大的测试类需要大约1:30m(包括上下文初始化时间)才能运行。

    我们的基本Dev VM类似于:

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

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

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

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

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

    总而言之,为什么Surefire的执行比在Eclipse上运行JUnit慢得多,有什么具体原因吗?我现在已经在这几天刮过头了,这真的开始惹恼我了!当解决方案看起来如此接近但是到目前为止,我讨厌它。

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

    我理解Maven有所有这些阶段等等,但区别不应该是这么大。你不同意吗?

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

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

    非常感谢!

    更新1

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

3 个答案:

答案 0 :(得分:1)

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

我知道surefire的fork设置非常复杂并且在一段时间内有所改变(详情请见https://maven.apache.org/surefire/maven-surefire-plugin/examples/fork-options-and-parallel-execution.html)。

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

你确定这是真正放慢速度的可靠测试吗?

答案 1 :(得分:1)

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

尝试完所有内容后,我们决定单独将测试执行配置带到此模块,跳过所有其他模块。这使套件执行从大约45'到22'。我们对此感到头疼,一旦我们理解了发生了什么,我将再次发布在这里。

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

感谢您的所有投入!

答案 2 :(得分:1)

我知道这是一个旧线程,但它可能仍然很有趣:如果你的工作负载使用了很多stdout或stderr,那么surefire将创建三倍于你输出的数组,以便将你的非转义输出保存到它们中。这比使用eclipse或gradle执行相同测试需要花费更多时间。

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