Der folgende Code sollte Ihre Anforderungen erfüllen, der aus dem deutschen Buch JUnit Profiwissen stammt, das einige Hinweise zum parallelen Testen von Inhalten oder zur Reduzierung der Ausführungszeit durch Verwendung mehrerer Kerne anstelle nur eines einzigen Kerns enthält.
JUnit 4.6 führte eine ParallelComputer-Klasse ein, die die parallele Ausführung von Tests bot. Diese Funktionalität war jedoch erst mit JUnit 4.7 öffentlich zugänglich, wodurch die Möglichkeit bestand, einen benutzerdefinierten Scheduler für den übergeordneten Runner festzulegen.
public class ParallelScheduler implements RunnerScheduler {
private ExecutorService threadPool = Executors.newFixedThreadPool(
Runtime.getRuntime().availableProcessors());
@Override
public void schedule(Runnable childStatement) {
threadPool.submit(childStatement);
}
@Override
public void finished() {
try {
threadPool.shutdown();
threadPool.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException("Got interrupted", e);
}
}
}
public class ParallelRunner extends BlockJUnit4ClassRunner {
public ParallelRunner(Class<?> klass) throws InitializationError {
super(klass);
setScheduler(new ParallelScheduler());
}
}
Wenn Sie jetzt eine Testklasse mit Anmerkungen versehen @RunWith(ParallelRunner.class)
, wird jede Methode in einem eigenen Thread ausgeführt. Darüber hinaus gibt es (nur) so viele aktive Threads, wie CPU-Kerne auf dem ausführenden Computer verfügbar sind.
Wenn mehrere Klassen gleichzeitig ausgeführt werden sollen, können Sie eine angepasste Suite wie folgt definieren:
public class ParallelSuite extends Suite {
public ParallelSuite(Class<?> klass, RunnerBuilder builder)
throws InitializationError {
super(klass, builder);
setScheduler(new ParallelScheduler());
}
}
und dann ändern @RunWith(Suite.class)
mit@RunWith(ParallelSuite.class)
Sie können sogar die Funktionalität von zB nutzen, WildcardPatternSuite
indem Sie direkt von dieser Suite aus erweitern, anstatt Suite
wie im vorherigen Beispiel. Auf diese Weise können Sie außerdem Unit-Tests nach Belieben filtern @Category
- eine TestSuite, die nur UnitTest
kommentierte Kategorien parallel ausführt, könnte folgendermaßen aussehen:
public interface UnitTest {
}
@RunWith(ParallelSuite.class)
@SuiteClasses("**/*Test.class")
@IncludeCategories(UnitTest.class)
public class UnitTestSuite {
}
Ein einfacher Testfall könnte nun so aussehen:
@Category(UnitTest.class)
@RunWith(MockitoJUnitRunner.class)
public class SomeClassTest {
@Test
public void testSomething() {
...
}
}
Das UnitTestSuite
führt jede Klasse aus, die in Unterverzeichnissen gefunden wird, die mit Test
einer @Category(UnitTest.class)
parallel angegebenen Klasse endet und diese hat - abhängig von der Anzahl der verfügbaren CPU-Kerne.
Ich bin mir nicht sicher, ob es einfacher werden kann :)