web-dev-qa-db-fra.com

Exécuter des tests junit en parallèle dans une construction Maven?

J'utilise JUnit 4.4 et Maven et j'ai un grand nombre de tests d'intégration de longue durée.

En ce qui concerne la mise en parallèle des suites de tests, quelques solutions me permettent d’exécuter chaque méthode de test dans une seule classe de tests en parallèle. Mais tout cela nécessite que je change les tests d’une manière ou d’une autre.

Je pense vraiment que ce serait une solution beaucoup plus propre d'exécuter X différentes classes de test dans des threads X en parallèle. J'ai des centaines de tests donc je ne me soucie pas vraiment de filer des classes de tests individuelles.

Est-ce qu'il y a un moyen de faire ça?

110
krosenvold

À partir de Junit 4.7, il est désormais possible d’effectuer des tests en parallèle sans utiliser TestNG. En réalité, cela a été possible depuis la version 4.6, mais un certain nombre de corrections apportées dans la version 4.7 en feront une option viable. Vous pouvez également exécuter des tests parallèles avec spring, ce que vous pouvez lire sur ici

40
krosenvold

Utilisez le plugin maven:

<build>
    <plugins>
    <plugin>
        <groupId>org.Apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.7.1</version>
        <configuration>
            <parallel>classes</parallel>
            <threadCount>5</threadCount>
        </configuration>
    </plugin>
    </plugins>
</build>
70
Oleksandr

Inspiré par le coureur expérimental ParallelComputer de JUnit, j'ai construit mon propre ParallelSuite et ParallelParameterized coureurs. En utilisant ces coureurs, on peut facilement paralléliser les suites de tests et les tests paramétrés.

ParallelSuite.Java

public class ParallelSuite extends Suite {

    public ParallelSuite(Class<?> klass, RunnerBuilder builder) throws InitializationError {

        super(klass, builder);

        setScheduler(new RunnerScheduler() {

            private final ExecutorService service = Executors.newFixedThreadPool(4);

            public void schedule(Runnable childStatement) {
                service.submit(childStatement);
            }

            public void finished() {
                try {
                    service.shutdown();
                    service.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
                } catch (InterruptedException e) {
                    e.printStackTrace(System.err);
                }
            }
        });
    }
}

ParallelParameterized.Java

public class ParallelParameterized extends Parameterized {

    public ParallelParameterized(Class<?> arg0) throws Throwable {

        super(arg0);

        setScheduler(new RunnerScheduler() {

            private final ExecutorService service = Executors.newFixedThreadPool(8);

            public void schedule(Runnable childStatement) {
                service.submit(childStatement);
            }

            public void finished() {
                try {
                    service.shutdown();
                    service.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
                } catch (InterruptedException e) {
                    e.printStackTrace(System.err);
                }
            }
        });
    }
}

L'utilisation est simple. Il suffit de remplacer @ RunWith la valeur des annotations par l’une de ces classes Parallèle * .

@RunWith(ParallelSuite.class)
@SuiteClasses({ATest.class, BTest.class, CTest.class})
public class ABCSuite {}
10
Mustafa Ulu

tempus-fugit propose quelque chose de similaire, consultez la documentation pour plus de détails. Il s'appuie sur JUnit 4.7 et vous marquez simplement votre test sur @RunWith(ConcurrentTestRunner).

À votre santé

5
Toby

Vous pouvez consulter la bibliothèque open source - Test Load Balancer . Il fait exactement ce que vous demandez - exécutez différentes classes de test en parallèle. Cela s’intègre au niveau ant-junit afin que vous n’ayez de toute façon pas besoin de changer vos tests. Je suis l'un des auteurs de la bibliothèque.

Pensez également à ne pas les exécuter dans les threads, car vous aurez peut-être besoin d'un sandbox de niveau processus. Par exemple, si vous utilisez une base de données dans vos tests d'intégration, vous ne voulez pas qu'un test échoue, car un autre test a ajouté des données dans un autre thread. La plupart du temps, les tests ne sont pas écrits dans cet esprit.

Enfin, comment avez-vous résolu ce problème jusqu'à maintenant?

3
Pavan

TestNG peut le faire (c'était mon premier réflexe - alors j'ai vu que vous aviez déjà beaucoup de tests).

Pour JUnit, regardez parallel-junit .

3
philant

Vous pouvez exécuter les tests en parallèle à l'aide de ParallelComputer fourni par Junit lui-même. Voici un petit extrait pour vous aider à démarrer.

Class[] cls = { TestCase1.class, TestCase2.class };
Result result = JUnitCore.runClasses(ParallelComputer.classes(), cls);
List<Failure> failures = result.getFailures();

Cela vous aidera lorsque vous aurez besoin d'exécuter des tests à partir de code car il ne dépend pas de Maven ni d'aucun autre outil de gestion de génération.

Veuillez noter que tous les cas de test seront exécutés en parallèle. Si vous avez des dépendances entre différents cas de test, cela pourrait entraîner de faux positifs. De toute façon, vous NE DEVRIEZ PAS avoir de tests interdépendants.

2
Ashwin Sadeep