web-dev-qa-db-fra.com

Comment puis-je inclure des classes de test dans le pot Maven et les exécuter?

Dans un projet Maven, j'ai des classes de test et des classes source dans le même package, mais dans des emplacements physiques différents.

.../src/main/Java/package/** <-- application code
.../src/test/Java/package/** <-- test code

Ce n'est pas un problème pour accéder aux classes source dans les classes de test, mais je voudrais exécuter un exécuteur de test dans la méthode principale et accéder à AllTest.class pour que je puisse créer un pot et exécuter mes tests.

 public static void main(String[] args) {
    // AllTest not found
    Result result = JUnitCore.runClasses(AllTest.class);
    for (Failure failure : result.getFailures()) {
        System.out.println(failure.toString());
    }
    System.out.println(result.wasSuccessful());
}

Mais cela ne fonctionne pas car je n'ai pas accès au code de test. Je ne comprends pas car ils sont dans le même paquet.

Question: comment accéder aux classes de test à partir des classes d'application? Sinon, comment Maven peut-il emballer un gros pot contenant des classes de test et exécuter des tests?

24
jam

Vous ne devez pas accéder aux classes de test à partir de votre code d'application, mais plutôt créer un principal (le même principal) dans la portée du test et créer un artefact supplémentaire pour votre projet.

Cependant, dans cet artefact supplémentaire (pot), vous devriez avoir:

  • Les classes de test
  • Les classes de code d'application
  • Dépendances externes requises par le code d'application (dans l'étendue compile)
  • Dépendances externes requises par le code de test (dans la portée test)

Ce qui signifie essentiellement un gros pot avec l'ajout de classes de test (et leurs dépendances). Le Maven Jar Plugin et son test-jar objectif ne répondrait pas à ce besoin. L'option Maven Shade Plugin et son option shadeTestJar n'aideraient pas non plus.

Alors, comment créer dans Maven un gros pot avec des classes de test et des dépendances externes?

Le Maven Assembly Plugin est un candidat parfait dans ce cas.

Voici un échantillon minimal de POM:

<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.sample</groupId>
    <artifactId>sample-project</artifactId>
    <version>1.0-SNAPSHOT</version>

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-Assembly-plugin</artifactId>
                <version>2.3</version>
                <configuration>
                    <descriptor>src/main/Assembly/assembly.xml</descriptor>
                </configuration>
                <executions>
                    <execution>
                        <id>make-Assembly</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                        <configuration>
                            <archive>
                                <manifest>
                                    <mainClass>com.sample.TestMain</mainClass>
                                </manifest>
                            </archive>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

La configuration ci-dessus définit la classe principale que vous avez définie dans vos classes de test. Mais cela ne suffit pas.

Vous devez également créer un fichier descripteur , dans le src\main\Assembly dossier et Assembly.xml fichier avec le contenu suivant:

<Assembly
    xmlns="http://maven.Apache.org/plugins/maven-Assembly-plugin/Assembly/1.1.3"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.Apache.org/plugins/maven-Assembly-plugin/Assembly/1.1.3 http://maven.Apache.org/xsd/Assembly-1.1.3.xsd">
    <id>fat-tests</id>
    <formats>
        <format>jar</format>
    </formats>
    <includeBaseDirectory>false</includeBaseDirectory>
    <dependencySets>
        <dependencySet>
            <outputDirectory>/</outputDirectory>
            <useProjectArtifact>true</useProjectArtifact>
            <unpack>true</unpack>
            <scope>test</scope>
        </dependencySet>
    </dependencySets>
    <fileSets>
        <fileSet>
            <directory>${project.build.directory}/test-classes</directory>
            <outputDirectory>/</outputDirectory>
            <includes>
                <include>**/*.class</include>
            </includes>
            <useDefaultExcludes>true</useDefaultExcludes>
        </fileSet>
    </fileSets>
</Assembly>

La configuration ci-dessus est:

  • définition des dépendances externes à extraire de l'étendue test (qui prendra également l'étendue compile)
  • définition d'un fileset pour inclure les classes de test compilées dans le cadre du pot de graisse emballé
  • définir un pot final avec fat-tests classifier (donc votre fichier final sera quelque chose comme sampleproject-1.0-SNAPSHOT-fat-tests.jar).

Vous pouvez ensuite appeler le principal comme suit (à partir du dossier target):

Java -jar sampleproject-1.0-SNAPSHOT-fat-tests.jar

À partir d'un tel principal, vous pouvez également appeler tous vos cas de test comme suit:

  • Créer une suite de tests JUni
  • Ajouter à la suite de tests les tests concernés
  • Appelez la suite de tests depuis votre plain Java main

Exemple de suite de tests:

import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;

@RunWith(Suite.class)
@SuiteClasses({ AppTest.class })
public class AllTests {

}

Remarque: dans ce cas, la suite de tests ne concerne que l'exemple de test AppTest.

Ensuite, vous pourriez avoir une classe principale comme suit:

import org.junit.internal.TextListener;
import org.junit.runner.JUnitCore;

public class MainAppTest {

    public static void main(String[] args) {
        System.out.println("Running tests!");

        JUnitCore engine = new JUnitCore();
        engine.addListener(new TextListener(System.out)); // required to print reports
        engine.run(AllTests.class);
    }
}

Le principal ci-dessus exécuterait alors la suite de tests qui exécutera en chaîne tous les tests configurés.

37
A_Di-Matteo