web-dev-qa-db-ja.com

JUnit4でテストメソッドを特定の順序で実行するにはどうすればいいですか?

@Testのアノテーションが付けられたテストメソッドを特定の順序で実行したいです。

例えば:

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

MyTestを実行するたびにtest1()の前にtest2()を実行するようにしたいのですが、@Test(order=xx)のようなアノテーションが見つかりませんでした。

JUnitの作者が order機能を望まないのであれば、それはJUnitにとって非常に重要な機能だと思います 、なぜですか。

379

JUnitの作成者が注文機能を必要としない場合、それはJUnitにとって非常に重要な機能だと思います。なぜですか?

私が知る限り、JUnitはすべてのテストを任意の順序で実行できると想定しているため、JUnitでこれを行うためのクリーンな方法があるかどうかはわかりません。 FAQから:

テストフィクスチャの使用方法

(...)テストメソッド呼び出しの順序は保証されていません。したがって、testEmptyCollection()の前にtestOneItemCollection()が実行される場合があります。 (...)

なぜそうなのですか?さて、テストの順序に依存するの作成は、著者が推奨したくないプラクティスであると考えています。テストは独立している必要があり、結合してはならず、これに違反するとwill物事の維持が難しくなり、テストを個別に実行する能力が損なわれます(明らかに)など.

そうは言っても、本当にこの方向に進みたい場合は、TestNGを使用することを検討してください。TestNGは、任意の順序でネイティブにテストメソッドを実行することをサポートします(メソッドの指定はメソッドのグループに依存します)。 Cedric Beustは、これを行う方法を testngでのテストの実行順序 で説明しています。

226
Pascal Thivent

既存のJunitのインスタンスを取り除き、 JUnit 4.11 またはそれ以上をビルドパスにダウンロードすると、次のコードはテストメソッドを名前の昇順で実行します。

@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");
    }
}
71
Aniket Kulkarni

順番が重要な場合は、自分で順番を決めてください。

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

特に、必要に応じて、テストする順序の一部または全部を並べ替える必要があります。

例えば、

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

または、すべての順列の完全検定

@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()はすべての可能な順列を配列のコレクションに繰り返す単純な関数です。

48
Xiè Jìléi

TestNGへの移行は最善の方法のようですが、ここではjUnitのための明確な解決策はわかりません。これが私が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(){}
}

これにより、ステージ2のメソッドがステージ1のメソッドの後でステージ3のメソッドの前に呼び出されるようになります。

40
joro

私がJunitに取り組んだときに私が直面した主な問題のその1つであり、私は私のためにうまく働く以下の解決策を思い付きました:

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;
    }
}

以下のようなインターフェースも作成します。

 @Retention(RetentionPolicy.RUNTIME)


@Target({ ElementType.METHOD})

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

以下のようないくつかのテストケースを書いたクラスAがあるとします。

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

void method(){

//do something

}

}

そのため、実行は "method()"という名前のメソッドから始まります。ありがとうございます。

17
Aman Goel

(まだリリースされていない)変更点 https://github.com/junit-team/junit/pull/386@SortMethodsWithを導入します。 https://github.com/junit-team/junit/pull/293 それがなくても順序は少なくとも予測可能になりました(Java 7ではそれはかなりランダムになる可能性があります)。

8
Jesse Glick

JUnitレポートを見てください。 JUnitはすでにパッケージごとにまとめられています。各パッケージにはTestSuiteクラスがあり(または持つことができます)、それぞれが複数のTestCaseを実行します。各TestCaseはpublic void test*()の形式の複数のテストメソッドを持つことができ、それぞれが実際にそれらが属するTestCaseクラスのインスタンスになります。各テストメソッド(TestCaseインスタンス)には、名前と合否基準があります。

私の管理が必要としているのは、個々の TestStep 項目の概念です。それぞれの項目は、それぞれ独自の合否基準を報告します。テストステップが失敗しても、後続のテストステップの実行を妨げてはいけません。

これまで、私の立場にあるテスト開発者は、テスト対象製品の一部に対応するパッケージにTestCaseクラスを編成し、各テスト用のTestCaseクラスを作成し、各テストメソッドをテスト内の別々の「ステップ」にしました。 JUnitの出力に独自の合格/不合格基準を入力します。各テストケースは独立した「テスト」ですが、テストケース内の個々のメソッド、またはテスト「ステップ」は特定の順序で実行する必要があります。

TestCaseメソッドはTestCaseのステップであり、テスト設計者はテストステップごとに別々の合否基準を取得しました。これでテストステップは混乱し、テストは(もちろん)失敗します。

例えば:

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

各試験方法はそれ自身の別々の合格/不合格基準を表明し報告する。順序付けのためにこれを「1つの大きなテスト方法」にまとめると、JUnitサマリーレポートの各「ステップ」の合否基準の細分性が失われます。 ...そしてそれは私の上司を怒らせる。彼らは現在別の選択肢を求めています。

スクランブルされたテストメソッドの順序を持​​つJUnitが、上に例示され、私の管理者によって要求されるように、各逐次テストステップの別々の合否基準をどのようにサポートするかを誰かが説明できますか?

ドキュメンテーションにかかわらず、私はこれをJUnitフレームワークの深刻な後退として見ています。これは多くのテスト開発者にとって人生を困難にしています。

6

JUnitでは現在、クラスアノテーションを使用してテストメソッドの順序付けを実行できます。

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

デフォルトでは、テストメソッドはアルファベット順に実行されます。そのため、特定のメソッドの順序を設定するには、次のように名前を付けます。

a_TestWorkUnit_WithCertainState_ShouldDoSomething b_TestWorkUnit_WithCertainState_ShouldDoSomething c_TestWorkUnit_WithCertainState_ShouldDoSomething

あなたは 例をここに見つけることができます

5
Zon

テストケースがスイートとして実行されている場合、あなたが望むことは完全に合理的です。

残念ながら、今すぐ完全なソリューションを提供する時間はありませんが、クラスを見てください。

org.junit.runners.Suite

これにより、特定の順序で(任意のテストクラスから)テストケースを呼び出すことができます。

これらは、機能テスト、統合テスト、またはシステムテストを作成するために使用される可能性があります。

このように実行してもしなくても、単体テストは特定の順序がないので(推奨どおり)、テストを全体像の一部として再利用します。

ユニットテスト、統合テスト、システムテスト、データ駆動型、コミット駆動型、スイートとして実行するために同じコードを再利用/継承します。

3
CharlieS

「ファイルのアップロード」をテストしてから「ファイルのアップロードによって挿入されたデータ」をテストする場合、これらが互いに独立しないようにしたくないのはなぜですか。完全に合理的私はそれらをGoliathテストケースに入れるのではなく別々に実行できると思います。

3
Mattk

ここで私の解決策を見てください: "Junit and Java 7"

この記事では、順調にjunitテストを実行する方法を説明します - 「ソースコードと同じように」。テストメソッドがクラスファイルに現れる順にテストが実行されます。

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

しかしPascal Thiventが言ったように、これは良い習慣ではありません。

2
kornero

JUnit 5.4では、順序を指定できます。

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

あなただけのあなたのクラスに注釈を付ける必要があります

@TestMethodOrder(OrderAnnotation.class)

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

私は私のプロジェクトでこれを使用しています、そしてそれは非常にうまくいきます!

0
Walid

これをチェックしてください: https://github.com/TransparentMarket/junit 。テストは指定された順序(コンパイル済みクラスファイル内で定義された順序)でテストを実行します。また、サブパッケージで定義されたテストを最初に実行するAllTestsスイートもあります。 AllTests実装を使用すると、プロパティのフィルタリングでも解決策を拡張できます(以前は@Fastアノテーションを使用しましたが、それらはまだ公開されていません)。

0
Martin Kersten

これはJUnitを拡張したもので、希望する動作を実現できます。 https://github.com/aafuks/aaf-junit

私はこれがJUnit哲学の作者に反することを知っていますが、厳密な単体テストではない環境でJUnitを使用する場合(Javaで実践されているように)、これは非常に役に立ちます。

0
shlomi33

あなたはこれらのコードの1つを使うことができます:

@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

私は自分のテストが順番通りに実行されなかったと思ってここに行きました、しかし真実は混乱が私の非同期ジョブにあったということです。並行性を扱うときは、テスト間でも並行性チェックを実行する必要があります。私の場合、ジョブとテストはセマフォを共有しているので、実行中のジョブがロックを解放するまで次のテストはハングします。

私はこれがこの質問と完全に関連していないことを知っていますが、正しい問題をターゲットにするのを助けるかもしれません

0
McCoy

私はいくつかの答えを読み、ベストプラクティスではないことに同意しますが、テストを順序付ける最も簡単な方法 - そしてJUnitがデフォルトでテストを実行する方法はアルファベット順の昇順です。

だからあなたが望むアルファベット順にあなたのテストに名前を付けるだけです。また、テスト名はWordテストで始まる必要があります。ただ気をつけろ

test12はtest2の前に実行されます

そう:

testA_MyFirstTest testC_ThirdTest testB_ATestThatRunsSecond

0
pstorli