web-dev-qa-db-fra.com

Comment exécuter des méthodes de test dans un ordre spécifique dans JUnit4?

Je souhaite exécuter des méthodes de test annotées par @Test dans un ordre spécifique.

Par exemple:

public class MyTest {
    @Test public void test1(){}
    @Test public void test2(){}
}

Je veux m'assurer d'exécuter test1() avant test2() chaque fois que je lance MyTest, mais je n'ai pas trouvé d'annotation comme @Test(order=xx).

Je pense que c'est une fonctionnalité très importante pour JUnit, si l'auteur de JUnit ne veut pas la fonctionnalité order , pourquoi?

371

Je pense que c'est une fonctionnalité très importante pour JUnit, si l'auteur de JUnit ne veut pas la fonctionnalité de commande, pourquoi? 

Je ne suis pas sûr qu'il existe un moyen propre de faire cela avec JUnit, à ma connaissance, JUnit suppose que tous les tests peuvent être effectués dans un ordre arbitraire. De la FAQ:

Comment utiliser un appareil de test?

(...) L'ordre des invocations de méthodes de test est non garanti, donc testOneItemCollection () peut être exécuté avant testEmptyCollection (). (...)

Pourquoi est-ce? Eh bien, je pense que faire des tests dépendants de l'ordre est une pratique que les auteurs ne veulent pas promouvoir. Les tests doivent être indépendants, ils ne doivent pas être couplés et ne pas violer cette volonté rend les choses plus difficiles à maintenir, annulera la capacité d'exécuter des tests individuellement (évidemment), etc.

Cela étant dit, si vous voulez vraiment aller dans cette direction, envisagez d'utiliser TestNG, car il prend en charge l'exécution de méthodes de test dans n'importe quel ordre de manière native (et des choses telles que la spécification de méthodes en fonction de groupes de méthodes). Cedric Beust explique comment faire cela dans ordre d'exécution des tests dans testng .

217
Pascal Thivent

Si vous supprimez votre instance existante de Junit et que vous téléchargez JUnit 4.11 ou une version supérieure dans le chemin de génération, le code suivant exécute les méthodes de test dans l'ordre de leurs noms, triés par ordre croissant:

@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class SampleTest {

    @Test
    public void testAcreate() {
        System.out.println("first");
    }
    @Test
    public void testBupdate() {
        System.out.println("second");
    }
    @Test
    public void testCdelete() {
        System.out.println("third");
    }
}
66
Aniket Kulkarni

Si la commande est importante, vous devez la faire vous-même. 

@Test public void test1() { ... }
@Test public void test2() { test1(); ... }

En particulier, vous devez répertorier tout ou partie des permutations possibles des commandes à tester, si nécessaire. 

Par exemple, 

void test1(); 
void test2(); 
void test3(); 


@Test
public void testOrder1() { test1(); test3(); }

@Test(expected = Exception.class)
public void testOrder2() { test2(); test3(); test1(); }

@Test(expected = NullPointerException.class)
public void testOrder3() { test3(); test1(); test2(); }

Ou, un test complet de toutes les permutations: 

@Test
public void testAllOrders() {
    for (Object[] sample: permute(1, 2, 3)) {
        for (Object index: sample) {
            switch (((Integer) index).intValue()) {
                case 1: test1(); break; 
                case 2: test2(); break; 
                case 3: test3(); break; 
            }
        }
    }
}

permute() est ici une fonction simple qui itère toutes les permutations possibles dans une collection de tableaux.

49
Xiè Jìléi

La migration vers TestNG semble être la meilleure solution, mais je ne vois pas de solution claire pour jUnit. Voici la plupart des solutions lisibles/formatage que j'ai trouvés pour jUnit:

@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class SampleTest {
    @Test
    void stage1_prepareAndTest(){};

    @Test
    void stage2_checkSomething(){};

    @Test
    void stage2_checkSomethingElse(){};

    @Test
    void stage3_thisDependsOnStage2(){};

    @Test
    void callTimeDoesntMatter(){}
}

Cela garantit que les méthodes stage2 sont appelées après les méthodes stage1 et avant celles de stage3. 

39
joro

C’est l’un des principaux problèmes auxquels j’ai été confronté lorsque j’ai travaillé sur Junit et j’ai trouvé la solution suivante qui me convient parfaitement:

import Java.util.ArrayList;
import Java.util.Collections;
import Java.util.Comparator;
import Java.util.List;

import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.InitializationError;

public class OrderedRunner extends BlockJUnit4ClassRunner {

    public OrderedRunner(Class<?> clazz) throws InitializationError {
        super(clazz);
    }

    @Override
    protected List<FrameworkMethod> computeTestMethods() {
        List<FrameworkMethod> list = super.computeTestMethods();
        List<FrameworkMethod> copy = new ArrayList<FrameworkMethod>(list);
        Collections.sort(copy, new Comparator<FrameworkMethod>() {

            @Override
            public int compare(FrameworkMethod f1, FrameworkMethod f2) {
                Order o1 = f1.getAnnotation(Order.class);
                Order o2 = f2.getAnnotation(Order.class);

                if (o1 == null || o2 == null) {
                    return -1;
                }

                return o1.order() - o2.order();
            }
        });
        return copy;
    }
}

créez également une interface comme ci-dessous:

 @Retention(RetentionPolicy.RUNTIME)


@Target({ ElementType.METHOD})

public @interface Order {
public int order();
}

Supposons maintenant que vous avez la classe A dans laquelle vous avez écrit plusieurs cas de test, comme ci-dessous:

(@runWith=OrderRunner.class)
Class A{
@Test
@Order(order = 1)

void method(){

//do something

}

}

Donc l'exécution commencera à partir de la méthode nommée "method ()" . Merci!

17
Aman Goel

Le changement (pas encore publié) https://github.com/junit-team/junit/pull/386 introduit un @SortMethodsWith. https://github.com/junit-team/junit/pull/293 a au moins rendu l'ordre prévisible sans cela (en Java 7, cela peut être assez aléatoire).

8
Jesse Glick

Regardez un rapport JUnit. JUnit est déjà organisé par paquet. Chaque paquet a (ou peut avoir) des classes TestSuite, chacune exécutant à son tour plusieurs TestCases. Chaque TestCase peut avoir plusieurs méthodes de test de la forme public void test*(), chacune d'entre elles devenant en réalité une instance de la classe TestCase à laquelle elles appartiennent. Chaque méthode de test (instance TestCase) a un nom et un critère de réussite/échec.

Ce que ma direction exige, c’est le concept d’individu TestStep , chacun indiquant son propre critère de réussite/d’échec. L'échec d'une étape de test ne doit pas empêcher l'exécution des étapes de test suivantes.

Auparavant, les développeurs de test de mon poste organisaient les classes TestCase en packages correspondant à la ou aux pièces du produit testé, créaient une classe TestCase pour chaque test et faisaient de chaque méthode de test une "étape" distincte dans le test. complète avec ses propres critères de réussite/échec dans la sortie JUnit. Chaque TestCase est un "test" autonome, mais les méthodes individuelles, ou "étapes" de test dans TestCase, doivent être exécutées dans un ordre spécifique.

Les méthodes TestCase étaient les étapes de TestCase et les concepteurs de test ont défini un critère de réussite/échec distinct par étape de test. Maintenant, les étapes de test sont mélangées et les tests échouent (bien sûr).

Par exemple:

Class testStateChanges extends TestCase

public void testCreateObjectPlacesTheObjectInStateA()
public void testTransitionToStateBAndValidateStateB()
public void testTransitionToStateCAndValidateStateC()
public void testTryToDeleteObjectinStateCAndValidateObjectStillExists()
public void testTransitionToStateAAndValidateStateA()
public void testDeleteObjectInStateAAndObjectDoesNotExist()
public void cleanupIfAnythingWentWrong()

Chaque méthode de test affirme et rapporte ses propres critères de réussite/échec distincts . Réduire cela en "une seule méthode de test" afin de commander perd la granularité des critères de réussite/échec de chaque "étape" du rapport de synthèse JUnit. ... et ça bouleverse mes gestionnaires. Ils exigent actuellement une autre alternative.

Quelqu'un peut-il expliquer comment une unité JUnit avec une commande de méthode de test brouillée prend en charge des critères de réussite/d'échec distincts pour chaque étape de test séquentielle, comme illustré ci-dessus et requis par ma direction?

Indépendamment de la documentation, je considère cela comme une régression sérieuse dans le framework JUnit qui rend la vie difficile à beaucoup de développeurs de tests.

6

JUnit autorise actuellement le classement des méthodes de test en utilisant des annotations de classe:

@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@FixMethodOrder(MethodSorters.JVM)
@FixMethodOrder(MethodSorters.DEFAULT)

Par défaut, les méthodes de test sont exécutées dans l'ordre alphabétique. Ainsi, pour définir un ordre de méthode spécifique, vous pouvez les nommer comme suit:

a_TestWorkUnit_WithCertainState_ShouldDoSething quelque chose b_TestWorkUnit_WithCertainState_ShouldDoSething quelque chose c_TestWorkUnit_WithCertainState_ShouldDoSchething

Vous pouvez trouver exemples ici .

5
Zon

Ce que vous voulez est parfaitement raisonnable lorsque les scénarios de test sont exécutés en tant que suite.

Malheureusement, pas le temps de donner une solution complète pour le moment, mais jetez un coup d'œil à la classe: 

org.junit.runners.Suite

Ce qui vous permet d'appeler des cas de test (de n'importe quelle classe de test) dans un ordre spécifique.

Ceux-ci peuvent être utilisés pour créer des tests fonctionnels, d'intégration ou de système.

Cela laisse vos tests unitaires comme ils sont sans ordre spécifique (comme recommandé), que vous les exécutiez de cette façon ou non, puis réutilisez les tests dans le cadre d’une image plus grande.

Nous réutilisons/héritons le même code pour des tests unitaires, d'intégration et système, parfois avec des données, parfois avec des validations et parfois avec une suite.

3
CharlieS

Pas sûr que je suis d'accord. Si je veux tester 'File Upload' puis 'Data Inserted by File Upload', pourquoi ne voudrais-je pas qu'elles soient indépendantes les unes des autres? Je pense être parfaitement raisonnable de pouvoir les exécuter séparément plutôt que d’avoir les deux dans un cas de test Goliath. 

3
Mattk

Voir ma solution ici: "Junit and Java 7."

Dans cet article, je décris comment exécuter des tests junit dans l’ordre - "exactement comme dans votre code source" . Des tests seront exécutés, car vos méthodes de test apparaissent dans le fichier class.

http://intellijava.blogspot.com/2012/05/junit-and-Java-7.html

Mais comme l'a dit Pascal Thivent, ce n'est pas une bonne pratique.

2
kornero

J'ai lu quelques réponses et je suis d'accord pour dire que ce n'est pas la meilleure pratique, mais le moyen le plus simple de commander vos tests - et que JUnit exécute les tests par défaut en procédant par ordre alphabétique croissant. 

Il suffit donc de nommer vos tests dans l’ordre alphabétique souhaité. Notez également que le nom du test doit commencer par le test Word. Attention aux chiffres

test12 s'exécutera avant test2

alors:

testA_MyFirstTest testC_ThirdTest testB_ATestThatRunsSecond

1
pstorli

Avec JUnit 5.4, vous pouvez spécifier l'ordre:

@Test
@Order(2)
public void sendEmailTestGmail() throws MessagingException {

il vous suffit d'annoter votre classe

@TestMethodOrder(OrderAnnotation.class)

https://junit.org/junit5/docs/current/user-guide/#writing-tests-tests-test-execution-order

je l'utilise dans mon projet et cela fonctionne très bien!

0
Walid

Veuillez vérifier celui-ci: https://github.com/TransparentMarket/junit . Il exécute le test dans l'ordre dans lequel ils sont spécifiés (défini dans le fichier de classe compilé). En outre, il comporte une suite AllTests permettant d’exécuter d’abord les tests définis par le sous-package. En utilisant l'implémentation AllTests, on peut étendre la solution en filtrant également les propriétés (nous utilisions auparavant des annotations @Fast mais celles-ci n'étaient pas encore publiées).

0
Martin Kersten

Voici une extension de JUnit pouvant produire le comportement souhaité: https://github.com/aafuks/aaf-junit

Je sais que cela va à l’encontre des auteurs de la philosophie JUnit, mais l’utilisation de JUnit dans des environnements qui ne sont pas des tests unitaires stricts (comme cela est le cas en Java) peut être très utile. 

0
shlomi33

vous pouvez utiliser l'un de ces codes:

@FixMethodOrder(MethodSorters.JVM)OR `@FixMethodOrder(MethodSorters.DEFAULT)` OR `@FixMethodOrder(MethodSorters.NAME_ASCENDING)` before your test class like this:


@FixMethodOrder(MethodSorters.NAME_ASCENDING)


public class BookTest { ...}
0
Arezoo Bagherzadi

Je me suis retrouvé ici en pensant que mes tests n'étaient pas organisés correctement, mais la vérité est que le désordre régnait dans mes tâches asynchrones. Lorsque vous travaillez avec concurrence, vous devez également effectuer des contrôles de concurrence entre vos tests . Dans mon cas, les travaux et les tests partagent un sémaphore, les tests suivants sont donc suspendus jusqu'à ce que le travail en cours relâche le verrou.

Je sais que cela n’est pas entièrement lié à cette question, mais je pourrais peut-être aider à cibler le bon problème.

0
McCoy