44 votes

Ordonner les tests unitaires dans la vue JUnit d'Eclipse

La vue JUnit dans Eclipse semble ordonner les tests de manière aléatoire. Comment puis-je les ordonner par nom de classe ?

7 votes

Cela me rend fou dans Eclipse, et j'aimerais que quelqu'un ajoute cette option au plugin. J'aimerais que la réponse acceptée corrige réellement le problème !

7voto

guerda Points 7417

Comme Gary l'a dit dans les commentaires :

ce serait bien si Unit Runner pouvait d'aller de l'avant et de les ordonner par nom de classe. Hmm, je devrais peut-être regarder dans le code source...

J'ai regardé mais il n'y a aucune indication d'une fonctionnalité pour trier ces noms. Je suggérerais bien une demande de changement au plugin JUnit, mais je ne pense pas qu'il y ait beaucoup de personnes qui utilisent cette chose, donc.. : BRICOLAGE.

J'aimerais voir la solution si vous modifiez le code du plugin.

0 votes

Oui, la meilleure solution est probablement de modifier le code du plugin. J'aimerais avoir le temps.

3voto

Martin Kersten Points 645

Une chose que l'on peut faire est d'utiliser le schéma de JUnit 3.x. Nous avons utilisé une suite de tests qui s'appelait AllTests où l'on ajoute les tests dans un ordre spécifique. Et pour chaque paquet, nous avions un autre AllTests. En donnant à ces suites de tests un nom identique à celui du paquet, on peut facilement construire une hiérarchie qui devrait être valorisée par le plugin junit.

Je n'aime vraiment pas la façon dont les méthodes de test sont présentées dans le visualiseur Junit. Elles devraient être présentées dans le même ordre que celui dans lequel elles sont spécifiées dans la classe TestCase. Je classe ces méthodes par ordre d'importance et de fonctionnalités. Ainsi, la méthode la plus défaillante est à corriger en premier, puis la plus spéciale dans la dernière partie du scénario de test.

C'est vraiment ennuyeux que le programme de test les brouille. Je vais y jeter un œil moi-même et si je trouve une solution, je mettrai à jour cette réponse.

Mise à jour :

Mon problème avec l'ordre des noms de méthodes dans un TestCase est lié à celui-ci : http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7023180 (Merci Oracle !).

Finalement, oracle a changé l'ordre des méthodes dans un appel class.getMethods ou class.getDeclaredMethods. Maintenant les méthodes sont aléatoires et peuvent changer entre les différentes exécutions de la JVM. Il semble que cela soit lié à des optimisations de comparaison ou même une tentative de compression du nom des méthodes - qui sait... .

Alors, que reste-t-il ? On peut d'abord utiliser : @FixMethodOrder (de javacodegeeks.com ):

  1. @FixMethodOrder(MethodSorters.DEFAULT) - ordre déterministe basé sur un comparateur interne
  2. @FixMethodOrder(MethodSorters.NAME_ASCENDING) - ordre ascendant des noms de méthodes
  3. @FixMethodOrder(MethodSorters.JVM) - manière pré 4.11 de dépendre de l'ordre basé sur la réflexion

C'est stupide, mais cela explique pourquoi les gens commencent à utiliser le schéma test1TestName.

Mise à jour2 :

J'utilise ASM car Javassist produit également des méthodes triées aléatoirement sur getMethods(). Ils utilisent Maps en interne. Avec ASM, j'utilise simplement un Visitor.

package org.junit.runners.model;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

import com.flirtbox.ioc.OrderTest;

/**
 * @author Martin Kersten
*/
public class TestClassUtil {
public static class MyClassVisitor extends ClassVisitor {
    private final List<String> names;
    public MyClassVisitor(List<String> names) {
        super(Opcodes.ASM4);
        this.names = names;
    }

    @Override
    public MethodVisitor visitMethod(int access, String name, String desc,
            String signature, String[] exceptions) {
        names.add(name);
        return super.visitMethod(access, name, desc, signature, exceptions);
    }
}

private static List<String> getMethodNamesInCorrectOrder(Class<?> clazz) throws IOException {
    InputStream in = OrderTest.class.getResourceAsStream("/" + clazz.getName().replace('.', '/') + ".class");
    ClassReader classReader=new ClassReader(in);
    List<String> methodNames = new ArrayList<>();
    classReader.accept(new MyClassVisitor(methodNames), 0);
    return methodNames;
}

public static void sort(Class<?> fClass, List<FrameworkMethod> list) {
    try {
        final List<String> names = getMethodNamesInCorrectOrder(fClass);
        Collections.sort(list, new Comparator<FrameworkMethod>() {
            @Override
            public int compare(FrameworkMethod methodA, FrameworkMethod methodB) {
                int indexA = names.indexOf(methodA.getName());
                int indexB = names.indexOf(methodB.getName());
                if(indexA == -1)
                    indexA = names.size();
                if(indexB == -1)
                    indexB = names.size();
                return indexA - indexB;
            }
        });
    } catch (IOException e) {
        throw new RuntimeException("Could not optain the method names of " + fClass.getName() + " in correct order", e);
    }
}
}

Il suffit de le placer dans votre dossier src/test/java dans le paquetage org.junit.runners.model. Copiez maintenant la classe org.junit.runners.model.TestClass de la librairie junit 4.5 dans le même paquetage et modifiez son constructeur en ajoutant la routine de tri.

 public TestClass(Class<?> klass) {
    fClass= klass;
    if (klass != null && klass.getConstructors().length > 1)
        throw new IllegalArgumentException(
                "Test class can only have one constructor");

    for (Class<?> eachClass : getSuperClasses(fClass))
        for (Method eachMethod : eachClass.getDeclaredMethods())
            addToAnnotationLists(new FrameworkMethod(eachMethod));

            //New Part
    for(List<FrameworkMethod> list : fMethodsForAnnotations.values()) {
        TestClassUtil.sort(fClass, list);
    }

    //Remove once you have verified the class is really picked up
    System.out.println("New TestClass for " + klass.getName());

}

Et voilà. Maintenant, vous avez joliment trié les méthodes dans l'ordre où elles sont déclarées dans le fichier java. Si vous vous posez la question, le chemin des classes est généralement défini de telle sorte que tout ce qui se trouve dans votre dossier src (target ou bin) est considéré en premier par le chargeur de classes. Ainsi, tout en définissant le même paquetage et la même classe, vous pouvez "surcharger" chaque classe/interface de toute bibliothèque que vous utilisez. Voilà l'astuce !

Mise à jour3 J'ai pu obtenir une vue arborescente de chaque paquet et de chaque classe dans le bon ordre.

  • L'idée est de sous-classer ParentRunner et d'y ajouter toutes les classes que vous identifiez comme étant publiques et dont les méthodes sont annotées avec test.
  • Ajoutez une méthode getName() qui ne renvoie que le nom du paquetage de la classe que le gestionnaire de la suite représente (de sorte que vous voyez l'arbre comme un arbre de paquetage sans le nom de la classe de la suite).
  • Inspectez les sous-répertoires si vous trouvez une certaine classe de suite (j'utilise AllTests pour toutes les classes de suite).
  • Si vous ne trouvez pas une classe de suite dans un sous-répertoire, vérifiez tous ses sous-répertoires, de cette façon vous ne manquerez pas un paquet contenant des tests si le répertoire parent ne contient pas de suite.

C'est tout. La classe de suite que j'ajoute partout est : @RunWith(MySuiteRunner.class) public class AllTests { }

C'est tout. Cela devrait vous donner assez pour commencer et étendre sur celui-ci. Le runner de la suite n'utilise que la réflexion mais je trie les classes de test et les suites des sous-répertoires par ordre alphabétique et les suites des sous-répertoires (qui représentent les paquets dans lesquels elles se trouvent) sont triées en haut.

2voto

guerda Points 7417

Mark a écrit :

il les ordonne en fonction du temps d'exécution, vous devriez peut-être trier vos méthodes ? source/tri des membres

mark a raison. Mais vous ne pouvez pas trier votre test unitaire. Il n'est pas permis de spéculer sur l'ordre d'exécution.

Les tests unitaires doivent être construits indépendamment et la façon dont ils sont appelés par le UnitRunner est aléatoire.

Dans la plupart des cas, les méthodes d'essai sont classées par ordre alphabétique. Les classes sont aléatoires. Essayez d'utiliser une TestSuite pour ordonner vos tests.

0 votes

J'essaie d'éviter d'utiliser TestSuite. J'apprécie l'indépendance des tests unitaires, et je la maintiens lors de leur création, mais ce serait bien si on pouvait dire à Unit Runner d'aller de l'avant et de les ordonner par nom de classe. Hmm, je devrais peut-être regarder dans le code source...

2voto

VonC Points 414372

Si vous avez vraiment besoin d'une dépendance forte entre vos tests JUnit, essayez Extension JExample

JExample introduit les relations producteur-consommateur dans les tests unitaires.
Un producteur est une méthode de test qui produit son unité testée comme valeur de retour.
Un consommateur est une méthode de test qui dépend d'un ou plusieurs producteurs et de leurs valeurs de retour.

Vous pouvez l'installer dans Eclipse pour Junit4.4 ou 4.5.

import jexample.Depends;

  @Test
  @Depends("#testEmpty") 
  public Stack<Integer> testPush(Stack<Integer> $) { 
      $.push(42); 
      assertFalse($.isEmpty()); 
      return $; 
  } 

Comme mentionné dans cet article d'IBM "A la recherche de la qualité du code : JUnit 4 vs. TestNG" :

Une chose que le framework JUnit essaie d'accomplir est isolement des tests .
En revanche, il est très difficile de spécifier un ordre d'exécution des scénarios de test, ce qui est essentiel pour tout type de test dépendant.
Les développeurs ont utilisé différentes techniques pour contourner ce problème, comme spécifier les cas de test par ordre alphabétique ou s'appuyer fortement sur les fixtures ( @Before @After ) pour mettre en place les choses correctement.

Ces solutions de contournement conviennent aux tests qui réussissent, mais pour les tests qui échouent, elles ont une conséquence gênante : chaque test dépendant suivant échoue également. Dans certaines situations, cela peut conduire à des suites de tests volumineuses signalant des échecs inutiles.

Alors attention : si vous retenez une solution pour ordonner vos tests JUnit comme vous le souhaitez... vous devez réfléchir si cette solution supporte une fonction "skip" afin de permettre aux autres tests de continuer même si l'un d'eux échoue.

2 votes

Je pense qu'il veut juste voir le résultats dans un ordre précis.

1 votes

... oui d'où ma réponse : puisque vous ne pouvez pas trier les résultats, vous pouvez essayer d'ordonner les tests.

2 votes

Oui, juste les résultats. Et seulement parce que je pourrais vouloir rechercher un résultat de test spécifique après l'exécution des tests unitaires. Je ne vois pas pourquoi Eclipse ne peut pas ordonner les résultats des tests au fur et à mesure de leur exécution. Il suffit d'utiliser un SortedSet.

-1voto

Je cherchais aussi une solution pour cela, et j'ai trouvé une sorte de crack à l'URL ci-dessous. Je ne sais pas si cela fonctionne pour vous ou non, mais cela a fonctionné pour moi dans Spring Tool Suite 2.5.2.

http://osdir.com/ml/java.junit.user/2002-10/msg00077.html

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X