web-dev-qa-db-fra.com

Junit: fractionnement du test d'intégration et des tests unitaires

J'ai hérité d'une charge de test Junit, mais ces tests (à l'exception de la plupart ne fonctionnent pas) sont un mélange de tests unitaires réels et de tests d'intégration (nécessitant des systèmes externes, une base de données, etc.).

J'essaie donc de trouver un moyen de les séparer, afin de pouvoir exécuter le test unitaire Nice et rapidement et les tests d'intégration par la suite.

Les options sont ..

  1. Divisez-les en répertoires séparés.

  2. Passez à Junit4 (à partir de la v3) et annotez les classes pour les séparer.

  3. Utilisez une convention de dénomination de fichier pour indiquer ce qu'est une classe, c'est-à-dire AdapterATest et AdapterAIntergrationTest.

3 a le problème qu'Eclipse a l'option "Exécuter tous les tests dans le projet/package ou dossier sélectionné". Il serait donc très difficile d'exécuter simplement les tests d'intégration.

2: court le risque que les développeurs commencent à écrire des tests d'intégration dans les classes de tests unitaires et cela devient tout simplement compliqué.

1: Cela semble être la solution la plus intéressante, mais mon instinct dit qu'il doit y avoir une meilleure solution.

Voilà ma question: comment séparer les tests d'intégration et les tests unitaires appropriés?

122
jeff porter

J'utilise actuellement des répertoires distincts en raison de la politique organisationnelle (et de l'héritage Junit 3), mais je cherche à passer moi-même aux annotations maintenant, je suis sur Junit 4.

Je ne serais pas trop préoccupé par le fait que les développeurs mettent des tests d'intégration dans vos classes de tests unitaires - ajoutez une règle dans vos normes de codage si nécessaire.

Je suis intéressé de savoir quelles sortes d'autres solutions pourraient exister en dehors des annotations ou de la séparation physique des classes.

10
Steven Mackenzie

Vous pouvez les diviser très facilement en utilisant les catégories JUnit et Maven.

Ceci est montré très, très brièvement ci-dessous en divisant les tests unitaires et d'intégration.

Définir une interface de marqueur

Cette interface sera utilisée pour marquer tous les tests que vous souhaitez exécuter en tant que tests d'intégration.

public interface IntegrationTest {}

Marquez vos classes de test

Ajoutez l'annotation de catégorie en haut de votre classe de test. Il prend le nom de votre nouvelle interface.

import org.junit.experimental.categories.Category;
@Category(IntegrationTest.class)
public class ExampleIntegrationTest{
  @Test
  public void longRunningServiceTest() throws Exception {
  }
}

Configurer les tests unitaires Maven

Nous ajoutons simplement une configuration au plugin maven surefire pour qu'il ignore tous les tests d'intégration.

<plugin>
  <groupId>org.Apache.maven.plugins</groupId>
  <artifactId>maven-surefire-plugin</artifactId>
  <version>2.11</version>
  <dependencies>
   <dependency>
     <groupId>org.Apache.maven.surefire</groupId>
     <artifactId>surefire-junit47</artifactId>
     <version>2.12</version>
   </dependency>
  </dependencies>
  <configuration>
    <includes>
      <include>**/*.class</include>
    </includes>
    <excludedGroups>com.test.annotation.type.IntegrationTest</excludedGroups>
  </configuration>
</plugin>

Lorsque vous effectuez un test de nettoyage mvn, seuls vos tests unitaires non marqués s'exécuteront.

Configurer les tests d'intégration Maven

Pour exécuter uniquement les tests d'intégration, utilisez ceci:

<plugin>
  <groupId>org.Apache.maven.plugins</groupId>
  <artifactId>maven-surefire-plugin</artifactId>
  <version>2.11</version>
  <dependencies>
   <dependency>
     <groupId>org.Apache.maven.surefire</groupId>
     <artifactId>surefire-junit47</artifactId>
     <version>2.12</version>
   </dependency>
  </dependencies>
  <configuration>
    <groups>com.test.annotation.type.IntegrationTest</groups>
  </configuration>
</plugin>

Si vous enveloppez cela dans un profil avec l'ID IT, vous ne pouvez exécuter que les tests rapides en utilisant mvn clean install. Pour exécuter uniquement les tests d'intégration/lents, utilisez mvn clean install -P IT.

Mais le plus souvent, vous voudrez exécuter les tests rapides par défaut et les tests tous avec -P IT. Si tel est le cas, vous devez utiliser une astuce:

<profiles>
    <profile>
        <id>IT</id>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.Apache.maven.plugins</groupId>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <configuration>
                        <excludedGroups>Java.io.Serializable</excludedGroups> <!-- An empty element doesn't overwrite, so I'm using an interface here which no one will ever use -->
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </profile>
</profiles>

Comme vous pouvez le voir, j'exclus les tests annotés avec Java.io.Serializable. Ceci est nécessaire car le profil héritera de la configuration par défaut du plugin Surefire, donc même si vous dites <excludedGroups/> Ou <excludedGroups></excludedGroups>, La valeur com.test.annotation.type.IntegrationTest Sera utilisée.

Vous ne pouvez pas non plus utiliser none car il doit s'agir d'une interface sur le chemin de classe (Maven vérifiera cela).

Remarques:

  • La dépendance à surefire-junit47 N'est nécessaire que lorsque Maven ne passe pas automatiquement au runner JUnit 4. L'utilisation de l'élément groups ou excludedGroups devrait déclencher le changement. Voir ici .
  • La plupart du code ci-dessus provient de la documentation du plugin Maven Failsafe. Voir la section "Utilisation des catégories JUnit" sur cette page .
  • Au cours de mes tests, j'ai constaté que cela fonctionne même lorsque vous utilisez des annotations @RunWith() pour exécuter des suites ou des tests basés sur Spring.
139
John Dobie

Nous utilisons Maven Surefire Plugin pour exécuter des tests unitaires et Maven Failsafe Plugin pour exécuter des tests d'intégration. Les tests unitaires suivent le **/Test*.Java **/*Test.Java **/*TestCase.Java conventions de dénomination, tests d'intégration - **/IT*.Java **/*IT.Java **/*ITCase.Java. C'est donc votre option numéro trois.

Dans quelques projets, nous utilisons TestNG et définissons différents groupes de tests pour les tests d'intégration/unitaires, mais cela ne vous convient probablement pas.

38
lexicore

Je passerais à Junit4 juste pour l'avoir :)

Vous pouvez les séparer en différentes suites de tests. Je ne sais pas comment ils sont organisés dans Junit3 mais cela devrait être facile dans Junit4 juste de construire des suites de tests et de mettre tous les vrais tests unitaires dans l'un d'entre eux, puis d'utiliser une deuxième suite pour les tests d'intégration.

Définissez maintenant une configuration d'exécution pour les deux suites dans Eclipse et vous pouvez facilement exécuter une seule suite. Ces suites pourraient également être lancées à partir d'un processus automatisé vous permettant d'exécuter les tests unitaires à chaque fois que la source change et peut-être les tests d'intégration (s'ils sont vraiment volumineux) seulement une fois par jour ou une fois par heure.

12
Janusz

L'utilisation de IfProfileValue annotation par ressort permet d'y parvenir sans un plugin maven ou une configuration requise.

Annoter les classes ou méthodes de test d'intégration à l'aide de IfProfileValue

import org.springframework.test.annotation.IfProfileValue;

@IfProfileValue(name="test-groups", value="integration")
public class ExampleIntegrationTest{
    @Test
    public void longRunningServiceTest() throws Exception {
    }
} 

Pour exécuter à l'aide de tests unitaires uniquement:

mvn clean test

Pour exécuter à l'aide du test d'intégration et des tests unitaires:

mvn clean test -Dtest-groups=integration

En outre, "Exécuter tous les tests" dans un IDE exécuterait uniquement le test unitaire. Ajoutez -Dtest-groups=integration à VM arguments pour exécuter à la fois les tests d'intégration et les tests unitaires.

8
Mit Mehta

Il n'y a pas de bonne réponse. Comme vous l'avez expliqué, il existe plusieurs façons de le faire qui fonctionneront. J'ai fait le schéma de nommage des fichiers et divisé les choses en différents répertoires.

Cela ressemble à la division de quelque chose en différents répertoires qui pourraient mieux fonctionner pour vous, et cela me semble un peu plus clair, alors je pencherais pour cela.

Je ne pense pas que j'essaierais les annotations car cela me semble plus fin. Voulez-vous vraiment que ces deux types de tests soient mélangés dans le même fichier? Je ne le ferais pas.

6
ndp