2014-03-29 7 views
7

Ich experimentiere mit Gradles Fähigkeit, Tests parallel auszuführen. Die Haupteinstellung, die ich gefunden habe, ist die maxParallelForks Eigenschaft von Test Aufgaben. Ich erwartete, dass das Verhalten dieser Einstellung ähnlich zu einem Executors.newFixedThreadPool ist, um die Tests auszuführen. Eine festgelegte Anzahl von Threads (Prozesse im Fall von Gradle) werden nämlich gleichzeitig ausgeführt; Immer wenn ein Thread die Arbeit beendet, wird eine neue im Pool aktiviert.Gradle: Lauftests parallel optimieren

Allerdings ist das Verhalten von Gradle auf eine weniger optimale Weise grundlegend anders. Es sieht so aus, als ob Gradle die Testklassen in eine Zahl gleich MaxParallelForks von Gruppen unterteilt, und dann erstellt Gradle einen Prozess für jede Gruppe und lässt diese Prozesse parallel ablaufen. Das Problem mit dieser Strategie liegt auf der Hand: Sie kann die Ausführung nicht dynamisch an die Zeit anpassen, die von einer Testklasse benötigt wird.

Angenommen, Sie haben 5 Klassen und maxParallelForks ist auf 2 gesetzt. Unter den fünf Klassen gibt es eine langsame und der Rest ist relativ schnell. Eine ideale Strategie wäre, wenn ein Prozess den langsamen ausführt und der andere die schnellen. Was Gradle jedoch tut, ist, den langsamen zusammen mit einem oder zwei schnellen zu gruppieren und zwei Prozesse zu erzeugen, um zwei Gruppen von Klassen auszuführen, was sicherlich weniger optimal als der Idealfall ist.

Hier ist eine einfache Demo.

Eine langsame Klasse:

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 
    } 
} 

Schnell Klassen (DemoTest2-4, mit gleicher Klasse Körper):

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 
    } 
} 

Alle Klassen sind im Paket junit, die der gleiche Name sein geschehen als ein berühmtes Testgerüst :-)

Hier ist ein möglicher Ausgang:

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 

Wie Sie sehen können, ist die langsame Klasse DemoTest mit zwei schnellen Klassen gruppiert. Die Gesamtlaufzeit beträgt etwa 13 Sekunden, was 10 Sekunden hätte sein können, wenn die schnellen Klassen zusammen gruppiert wären.

Gibt es also eine einfache Möglichkeit, dieses Verhalten in Gradle zu optimieren, ohne auf einen benutzerdefinierten JUnit-Runner zurückzugreifen?

Vielen Dank.

Antwort

1

Dies kann nur durch Änderungen an der Codebase von Gradle optimiert werden.