web-dev-qa-db-fra.com

Spécification de l'ordre d'exécution dans le cas de test JUnit

J'ai un cas de test où j'ajoute une entité, la met à jour et la supprime. Par conséquent, l'ordre d'exécution est important ici. Je veux que ce soit:

  1. Créer
  2. Mise à jour
  3. Supprimer

Étrangement, pour un seul cas de test (sur 15), JUnit l'exécute dans l'ordre suivant:

  1. Supprimer
  2. Mise à jour
  3. Créer .

Comment dire à JUnit de les exécuter dans un ordre spécifique? Dans d'autres cas, JUnit fonctionne parfaitement (exécution en série). Et pourquoi JUnit se comporte-t-il bizarrement dans ce cas?

Extrait de code pertinent ci-dessous:

    private static Date date;
    private static int entity;
    static Parking p;
    public ParkingTests(String name) {
       super(name);
    }
    public void testAdd() throws Exception {
           //Add code here
    }
    public void testUpdate() throws Exception {
            //update code here
    }
    public void testDelete() throws Exception {
            //delete code here
    }
  }

Cela devient plus étrange. J'exécute beaucoup de cas de test dans le cadre d'une suite. Si je lance uniquement la valise Parking, la commande est maintenue. Si je le fais avec d'autres, il est parfois entretenu, parfois non!

19
crazyaboutliv

Votre type de situation est gênant, car il est désagréable de continuer à dupliquer le travail afin d'isoler les tests (voir ci-dessous) - mais notez que la plupart des la duplication peut être extraite dans setUp et tearDown (@Before, @After), vous n'avez donc pas besoin de beaucoup de code supplémentaire. À condition que les tests ne s'exécutent pas si lentement que vous arrêtez de les exécuter souvent, il est préférable de gaspiller un peu de CPU au nom de tests propres.

public void testAdd() throws Exception {
      // wipe database
      // add something
      // assert that it was added
}
public void testUpdate() throws Exception {
      // wipe database
      // add something
      // update it
      // assert that it was updated
}
public void testDelete() throws Exception {
      // wipe database
      // add something
      // delete it
      // assert that it was deleted
}

L'alternative est de tout coller dans un test avec plusieurs assertions, mais cela est plus difficile à comprendre et à maintenir, et donne un peu moins d'informations lorsqu'un test échoue:

public void testCRUD() throws Exception {
      // wipe database
      // add something
      // assert that it was added
      // update it
      // assert that it was updated
      // delete it 
      // assert that it was deleted
}

Les tests avec des bases de données ou des collections ou le stockage de tout type sont délicats car un test peut toujours affecter d'autres tests en laissant des ordures dans la base de données/collection. Même si vos tests ne reposent pas explicitement les uns sur les autres, ils peuvent toujours interférer les uns avec les autres, surtout si l'un d'eux échoue.

Dans la mesure du possible, utilisez une nouvelle instance pour chaque test ou effacez les données, idéalement de la manière la plus simple possible - par ex. pour une base de données, l'effacement d'une table entière a plus de chances de réussir qu'une suppression très spécifique que vous pourriez accidentellement vous tromper.

pdate: Il est généralement préférable d'effacer les données au début du test, donc un test échoué n'affecte pas le prochain.

18
DNA

En règle générale, les tests junit (méthodes de test) ne devraient pas dépendre les uns des autres. Ce qui suit est tiré de junit FAQ

Chaque test s'exécute dans son propre appareil de test pour isoler les tests des modifications apportées par d'autres tests. Autrement dit, les tests ne partagent pas l'état des objets dans le montage de test. Les tests étant isolés, ils peuvent être exécutés dans n'importe quel ordre ... La commande des appels de méthode de test n'est pas garantie.

Donc, si vous voulez faire des trucs d'initialisation courants, vous pouvez le faire dans la méthode annotée avec @Before et nettoyage dans la méthode annotée avec @After. Ou bien, si cette initialisation n'est pas requise pour toutes les méthodes de test de votre classe de test, vous pouvez mettre cela dans des méthodes privées et les appeler de manière appropriée à partir de vos tests.

Sur une note latérale, si vous voulez toujours faire l'ordre des tests, vous pouvez jeter un œil à TestNG.

19
Kuldeep Jain

Si vous êtes déterminé que vous souhaitez avoir un ordre d'exécution pour vos tests, JUnit 4.11 prend désormais cela en charge grâce à une annotation. Voir ce fil pour plus de discussion - en gros, vous utiliseriez

@FixMethodOrder

pour garantir un certain ordre de test de cette façon. C'est découragé cependant.

12
eis

Si vous utilisez Java 7 , vous devez savoir que Junit obtient la liste de tous les tests à l'aide de "Method [] getDeclaredMethods ()" de Java.lang. Classe. Vous pouvez lire dans le javadoc de cette méthode ou dans les documents junit que: " Les éléments du tableau retourné ne sont pas triés et ne sont pas dans un ordre particulier. ", mais dans les précédentes méthodes d'implémentation jvm, la liste était ordonnée comme dans le code source.

Cela a été tiré de ce blog et il fournit un travail autour.

7
Joshua Wilson

En général, JUnit ne garantit pas la commande des cas de test. Ce n'est pas garanti d'être alphabétique, ni l'ordre dans le fichier. Si l'ordre des tests était important, alors l'un dépend de la sortie du précédent. Et si le premier échouait? Faut-il même s'embêter avec les tests ultérieurs (et dépendants)? Probablement pas.

Donc, si nous avions ceci:

@Test
public void first(){...}

@Test
public void second() {...}

@Test
public void third() {...}

Nous ne savons pas dans quel ordre ils s'exécuteront. Puisque nous espérons qu'ils vont dans l'ordre, et nous ne devrions probablement pas prendre la peine d'exécuter le deuxième ou le troisième si le ou les précédents ont échoué, nous pouvons le faire à la place:

@Test
public void firstThree(){
    first();
    second();
    third();
}

public void first(){...}
public void second() {...}
public void third() {...}

Notez que nous n'avons qu'un seul @Test cette fois, et cela garantit la commande.

5
mudd

Si vous souhaitez exécuter les tests junit dans l'ordre "tout comme ils le présentent dans votre code source", consultez ma note à ce sujet ici:

Comment exécuter les tests junit dans l'ordre tel qu'ils se présentent dans votre code source

Mais ce n'est vraiment pas une bonne idée, les tests doivent être indépendants.

2
kornero

Ce que tu peux faire :

  • Nettoyer la base de données avant chaque test
  • Commencez par tester la première opération logique en premier. Lorsque vous avez suffisamment confiance, supposez que c'est correct et passez à la suivante, etc ...
  • Écrivez d'abord les tests de boîte blanche, mais commencez par les tests de boîte noire. Par exemple, si vous avez des déclencheurs ou similaires dans votre base de données, commencez par cela.
1
UmNyobe