Gradle:优化并行运行测试



我正在试验Gradle并行运行测试的能力。我发现的主要设置是测试任务的maxParallelForks属性。我期望该设置的行为类似于使用Executors.newFixedThreadPool来执行测试。也就是说,固定数量的线程(在Gradle的情况下是进程)正在并发执行;每当一个线程完成工作时,池中就会激活一个新的线程。

然而,Gradle的行为以一种不太理想的方式从根本上不同。看起来Gradle将测试类划分为一个等于maxParallelForks组的数字,然后Gradle为每个组生成一个进程,并让这些进程并行执行。这种策略的问题很明显:它不能根据测试类所需的时间动态调整执行。

例如,假设您有5个类,maxParallelForks被设置为2。在五个班中,有一个慢班,其余的都比较快。理想的策略是让一个进程执行慢进程,另一个进程执行快进程。然而,Gradle所做的是将慢的进程与一个或两个快速的进程组合在一起,并生成两个进程来执行两组类,这当然不如理想情况下最优。

下面是一个简单的示例。

一个慢类:

class DemoTest {
    @Test
    void one() {
        Thread.sleep( 5000 )
        println System.getProperty('org.gradle.test.worker') + ": " + new Date().format('HH:mm:ss')
        assert 1 == 1
    }
    @Test
    void two() {
        Thread.sleep( 5000 )
        println System.getProperty('org.gradle.test.worker') + ": " + new Date().format('HH:mm:ss')
        assert 1 == 1
    }
}

快速类(DemoTest2-4,类体相同):

class DemoTest2 {
    @Test
    void one() {
        Thread.sleep( 1000 )
        println System.getProperty('org.gradle.test.worker') + ": " + new Date().format('HH:mm:ss')
        assert 1 == 1
    }
    @Test
    void two() {
        Thread.sleep( 1000 )
        println System.getProperty('org.gradle.test.worker') + ": " + new Date().format('HH:mm:ss')
        assert 1 == 1
    }
}

所有的类都在junit包中,它恰好与一个著名的测试框架同名:-)

下面是一个可能的输出:

junit.DemoTest2 > one STANDARD_OUT
    2: 14:54:00
junit.DemoTest2 > two STANDARD_OUT
    2: 14:54:01
junit.DemoTest4 > one STANDARD_OUT
    2: 14:54:02
junit.DemoTest4 > two STANDARD_OUT
    2: 14:54:03
junit.DemoTest > one STANDARD_OUT
    3: 14:54:04
junit.DemoTest > two STANDARD_OUT
    3: 14:54:09
junit.DemoTest3 > one STANDARD_OUT
    3: 14:54:10
junit.DemoTest3 > two STANDARD_OUT
    3: 14:54:11
junit.DemoTest5 > one STANDARD_OUT
    3: 14:54:12
junit.DemoTest5 > two STANDARD_OUT
    3: 14:54:13

可以看到,慢类DemoTest与两个快类分组。总运行时间约为13秒,如果将快速类分组在一起,则可能是10秒。

那么,有没有什么直接的方法可以在Gradle中优化这种行为而不诉诸于自定义JUnit运行程序?

这只能通过更改Gradle代码库来优化。