web-dev-qa-db-ja.com

EclipseJUnitビューでの単体テストの注文

EclipseのJUnitビューは、テストをランダムに順序付けているようです。クラス名で注文するにはどうすればよいですか?

40
Gary Kephart

ゲイリーがコメントで言ったように:

ユニットランナーにクラス名で注文するように指示できればいいのですが。うーん、多分私はソースコードを調べる必要があります...

私は見ましたが、これらの名前をソートする機能のヒントはありません。 JUnitプラグインへの変更リクエストをお勧めしますが、これを使用している人はあまりいないと思います。つまり、DIYです。

プラグインコードを変更した場合の解決策を確認したいと思います。

6
guerda

JUnit3.xのスキーマを使用することもできます。 AllTestsと呼ばれるテストスイートを使用し、特定の順序でテストを追加しました。そして、すべてのパッケージに対して、別のAllTestsを取得しました。これらのテストスイートにパッケージと同じ名前を付けると、junitプラグインで評価する必要のある階層を簡単に構築できます。

Junitビューア内でテストメソッドを表示する方法が本当に嫌いです。 TestCaseクラスで指定されている順序とまったく同じである必要があります。私はそれらのメソッドを重要性と機能の方法で注文します。したがって、最も失敗する方法は、最初に修正し、次にテストケースの後半でより特別な方法を修正することです。

テストランナーがそれらをスクランブリングしているのは本当に迷惑です。私はそれを自分で見て、解決策を見つけたらこの答えを更新します。

更新:

TestCase内のメソッド名の順序に関する私の問題は、これに関連しています: http://bugs.Sun.com/bugdatabase/view_bug.do?bug_id=702318 (Oracleに感謝します!)。

そのため、最終的にOracleは、class.getMethodsまたはclass.getDeclaredMethods呼び出し内のメソッドの順序を変更しました。現在、メソッドはランダムであり、JVMの異なる実行間で変更できます。それは、比較の最適化に関連しているとか、メソッド名を圧縮する試みでさえあります-誰が知っていますか..。

だから何が残った。最初のものは使用できます:@FixMethodOrder(from javacodegeeks.com ):

  1. @FixMethodOrder(MethodSorters.DEFAULT)–内部コンパレータに基づく決定論的順序
  2. @FixMethodOrder(MethodSorters.NAME_ASCENDING)–メソッド名の昇順
  3. @ FixMethodOrder(MethodSorters.JVM)–リフレクションベースの順序に依存する4.11より前の方法

それはばかげていますが、なぜ人々がtest1TestNameスキーマを使い始めるのかを説明しています。

Update2

JavassistはgetMethods()でランダムにソートされたメソッドも生成するため、ASMを使用します。内部でマップを使用します。 ASMでは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);
    }
}
}
_

これをパッケージorg.junit.runners.modelのsrc/test/Javaフォルダーに入れるだけです。次に、junit 4.5 libのorg.junit.runners.model.TestClassを同じパッケージにコピーし、ソートルーチンを追加してコンストラクターを変更します。

_ 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());

}
_

どうぞ。これで、Javaファイル内で宣言された順序でメソッドが適切にソートされました。クラスパスは通常、src(ターゲットまたはbin)フォルダー内のすべてが考慮されるように設定されています。最初はクラスローダーによってです。したがって、まったく同じパッケージと同じクラスを定義しながら、使用するライブラリ内のすべてのクラス/インターフェイスを「オーバーライド」できます。これがトリックです。

Update3すべてのパッケージとすべてのクラスのツリービューを正しい順序で取得できました。

  • アイデアは、ParentRunnerをサブクラス化してから、パブリックであり、メソッドにtestアノテーションが付けられていると識別したすべてのクラスをそれに追加することです。
  • スイートランナーが表しているクラスのパッケージ名のみを返すgetName()メソッドを追加します(したがって、ツリーはスイートのクラス名のないパッケージツリーとして表示されます)。
  • 特定のスイートクラスが見つかった場合は、サブディレクトリを調べます(すべてのスイートクラスにAllTestsを使用します)。
  • サブディレクトリにスイートクラスが見つからない場合は、そのすべてのサブディレクトリを確認してください。これにより、親ディレクトリにスイートが含まれていない場合に、テストを含むパッケージを見逃すことはありません。

それだけです。私がどこにでも追加するスイートクラスは次のとおりです。@RunWith(MySuiteRunner.class) public class AllTests { }

それでおしまい。これを開始して拡張するのに十分な量を与える必要があります。スイートランナーはリフレクションのみを使用していますが、テストクラスとサブディレクトリのスーツをアルファベット順に並べ替え、サブディレクトリのスーツ(それらが含まれるパッケージを表す)を一番上に並べ替えています。

3
Martin Kersten

マークは書いた:

それは実行時間に基づいてそれらを注文します、多分あなたはあなたのメソッドをソートするべきですか?ソース/ソートメンバー

マークは正しいです。ただし、単体テストを並べ替えることはできません。実行の順序について推測することは許可されていません。

ユニットテストは独立して構築する必要があり、UnitRunnerによってどのように呼び出されるかはランダムです。

ほとんどの場合、テスト方法はアルファベット順にソートされています。クラスはランダムです。 TestSuiteを使用してテストを注文してみてください。

2
guerda

JUnitビューでの注文テストは Eclipse Bugzillaのバグ#38645 として提出されています。そこでコメントしたり投票したりすると、この問題をより明確に把握できるようになる可能性があります。

2
mrts

JUnitテスト間の強い依存関係が本当に必要な場合は、JExample拡張を試してください。

JExampleは、ユニットテストに生産者/消費者関係を導入します。
プロデューサーは、テスト対象のユニットを戻り値として生成するテストメソッドです。
コンシューマーは、1つ以上のプロデューサーとその戻り値に依存するテストメソッドです。

Junit4.4または4.5の場合、 Eclipseにインストール できます。

import jexample.Depends;

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

このIBMの記事で述べたように "コード品質の追求:JUnit 4とTestNG"

JUnitフレームワークが達成しようとしていることの1つは、テスト分離です。
欠点として、これにより、テストケースの実行順序を指定することが非常に困難になります。これは、あらゆる種類の依存テストに不可欠です。
開発者は、テストケースをアルファベット順に指定したり、フィクスチャに大きく依存したりするなど、これを回避するためにさまざまな手法を使用しています(@Before@After)適切に設定します。

これらの回避策は、成功するテストには問題ありませんが、失敗するテストの場合、不便な結果になります。後続のすべての依存テストも失敗します。状況によっては、これにより、大規模なテストスイートが不要な障害を報告する可能性があります

したがって、注意してください。JUnitテストを希望どおりに注文するためのソリューションを保持している場合は、そのソリューションが「スキップ」機能をサポートしているかどうかを検討して、いずれかのテストが失敗した場合でも他のテストを続行できるようにする必要があります。

2
VonC

私もこれの解決策を探していました、そして私は以下のURLから一種の亀裂を見つけました。それがあなたのために働くかどうかはわかりませんが、Spring ToolSuite2.5.2ではうまくいきました。

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

0