JUnit4でテストメソッドを特定の順序で実行する方法


413

@Test特定の順序で注釈が付けられたテストメソッドを実行したい。

例えば:

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

実行するtest1()前に必ず実行したいのですtest2()MyTest、のような注釈が見つかりませんでした@Test(order=xx)

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


2
これらは、ソースファイルに表示される順序で実行されるように見えます。
ローン侯爵

84
指定した順序で実行する必要のあるテストを記述してはなりません。それは本当に悪い習慣です。すべてのテストは独立して実行できる必要があります。
Apfelsaft 2012

5
@EJPこれは、Java 7より前のほとんどすべてに当てはまりました。7より前のほとんどのJVMでは、これが行われていましたが、保証されていませんでした。Java 7 JVMは、メソッドを非決定的な順序で返す場合があります。
マシューファーウェル

17
回避してください。テストケースから@Testを削除し、プライベート関数として変換してから、単一のテストケースを作成し、プライベート関数を順番に呼び出します。
Simon Guo

12
テストケースから@Testを削除すると、JUnitレポートが混乱します。ちなみに、特定の順序を強制することは、単体テストでは悪い習慣ですが、統合テストでは必ずしも悪い習慣ではありません。最良の選択は(ない理想的な)を持つクラスに注釈を付けることで@FixMethodOrder(MethodSorters.NAME_ASCENDING)、維持@Test、例えば、すべての試験方法のための注釈をし、実行の所望の順序に応じて、アルファベット順に名前を変更t1_firstTest()t2_secondTest()など
MisterStrickland

回答:


238

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

私の知る限り、JUnitはすべてのテストを任意の順序で実行できると想定しています。FAQから:

テストフィクスチャの使用方法を教えてください。

(...)テストメソッド呼び出しの順序は保証されていないため、testOneItemCollection()はtestEmptyCollection()の前に実行される可能性があります。(...)

なぜそうなのですか?まあ、私はテストを順序に依存させることは著者が促進したくない習慣だと信じています。テストは独立している必要があり、結合してはなりません。これ違反する、保守が困難になったり、テストを個別に(明らかに)実行したりできなくなります。

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


14
2つの独立したテストがあるか、1つのテストしかなく、そのようにコーディングする必要があります。
Jon Freedman、2009

2
@JonFreedman、私が質問を理解しているように、テストが相互に依存しているというわけではなく、テストする仕様のスペックがあり、結果をその順序で表示したいだけです。
ジョンブライト

174
単体テストの順序を強制しないことは理解できますが、JUnitを使用して統合テストを作成する場合、テストを実行する順序を指定できると便利です。たとえば、最初にログインテストを実行します。
Brian DiCasa

13
@BrianD。ログインは、おそらく他のすべての前に実行する必要があるテストではなく、「フィクスチャ」です。ログインするBeforeClassを作成してから、任意の順序で実行するテストを作成します。
marcospereira 2012年

47
「テストは独立である必要がある=>テストはORDER独立である必要がある」という意味は正しくありません。学生の宿題の自動採点を検討してください。最初に小さい入力に対してソリューションをテストし、後で大きい入力に対してテストしたいと思います。(時間/メモリ制限のために)入力が小さい場合にソリューションが失敗する場合、テストは大きい入力に対して実行する必要があるのはなぜですか?
mirelon 2013年

96

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

8
実際に同様のメソッドtest_001_login()を実際に試しましたが、ほとんどの場合順序を維持するように機能しますが、保証はされません。テスト実行ごとに、004、005、および006が007の後に実行されるインスタンスがいくつかあります。あなたは「WTF!」と言って、答えを得るためにStackOverflowに実行します。
Max P Magee 2014年

素晴らしい
-JUnit

1
私のテストでは:testAcase-機能しました、test_A_case / testA_case-しませんでした!
Rodislavモルドバン、2016

6
このアノテーションパラメータ「MethodSorters.JVM」、たとえば「@FixMethodOrder(MethodSorters.JVM)」を試しました。APIから:JVM-テストメソッドをJVMから返された順序のままにします。、私の私は(CRUD)をやっている何のためにうまく動作しますが、それらに書かれている順にテストメソッドを実行します1。
Edvinauskas

1
この注釈は確かに回答ですが、(Junit 4.12で)で定義さ@Inheritedれていないため、私のAbstractTestCase親クラスでは無効になるという警告があります。
AbVog 2018

49

注文が重要な場合は、自分で注文する必要があります。

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


しかし、別のファイルでテストするとどうなるでしょうか。
Oleg Abrazhaev 16年

3
最初のコードブロックで、再度test2実行test1 ます。JUnitはまだ実行できますtest2前にtest1。これはおそらくあなたが意図したものではなく、質問に対する有効な答えではありません。
toolforger 2018年

47

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

これにより、stage1メソッドの後で、stage3メソッドの前に、stage2メソッドが確実に呼び出されます。


5
このアプローチは良いですが、10個を超えるテストがある場合、0接頭辞を追加しないとうまく機能しないことを言及することは有効です。たとえばvoid stage01_prepareAndTest(){ }
EliuX

10以上のステージがある場合(テストではない) -はい。可能な場合は、ステージの数を制限し、各ステージでテストを増やすことをお勧めします。
joro

18

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()」という名前のメソッドから開始されます。よろしくお願いします!


PowerMockでの別のJUnitランナーの使用バージョン1.6.0以降、PowerMockでは、JUnitルールを使用せずにテスト実行を別のJUnitランナーに委任することができます。これにより、実際のテスト実行は選択した別のランナーに委ねられます。 @RunWith(PowerMockRunner.class) @PowerMockRunnerDelegate(OrderedRunner.class)
Kyriakos Georgiopoulos

11

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

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

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

a_TestWorkUnit_WithCertainState_ShouldDoSomething b_TestWorkUnit_WithCertainState_ShouldDoSomething c_TestWorkUnit_WithCertainState_ShouldDoSomething

あなたは見つけることができ、ここでの例を


8

(まだ未発表)の変化https://github.com/junit-team/junit/pull/386紹介A @SortMethodsWithhttps://github.com/junit-team/junit/pull/293は、少なくともそれなしで注文を予測可能にしました(Java 7では、かなりランダムになる可能性があります)。


1
#386は4.11で統合されたようです。
ジェシーグリック

このページの下でさらに説明されているように、実際には4.11では呼び出されて@FixMethodOrderいません@SortMethodsWith
vorburger

6

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

私の管理に必要なのは、それぞれが独自の合格/不合格基準を報告する個別のTestStep項目の概念です。テストステップの失敗は、後続のテストステップの実行を妨げてはなりません。

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

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 5の更新(および私の意見)

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

デフォルトでは、ユニットテストライブラリは、ソースファイルで発生する順序でテストを実行しようとしません。
JUnit 4としてのJUnit 5はそのように動作します。どうして ?順序が重要な場合は、いくつかのテストがそれらの間で結合されており、単体テストに望ましくないためです。
したがって、@NestedJUnit 5によって導入された機能は、同じデフォルトのアプローチに従います。

ただし、統合テストでは、テストメソッドが別のテストメソッドで予期される方法でアプリケーションの状態を変更する可能性があるため、テストメソッドの順序が重要になる場合があります。たとえば、eショップのチェックアウト処理の統合テストを作成する場合、最初に実行されるテストメソッドはクライアントを登録し、2番目はバスケットにアイテムを追加し、最後のメソッドはチェックアウトを実行します。テストランナーがその順序を尊重しない場合、テストシナリオに欠陥があり、失敗します。
したがって、JUnit 5(5.4バージョンから)では、テストクラスに注釈を付け@TestMethodOrder(OrderAnnotation.class)、順序を指定することで実行順序を設定する可能性はすべて同じです。@Order(numericOrderValue)、順序が重要なメソッドのです。

例えば ​​:

@TestMethodOrder(OrderAnnotation.class) 
class FooTest {

    @Order(3)
    @Test
    void checkoutOrder() {
        System.out.println("checkoutOrder");
    }

    @Order(2)
    @Test
    void addItemsInBasket() {
        System.out.println("addItemsInBasket");
    }

    @Order(1)
    @Test
    void createUserAndLogin() {
        System.out.println("createUserAndLogin");
    }
}

出力:

createUserAndLogin

addItemsInBasket

checkoutOrder

ちなみに、指定 @TestMethodOrder(OrderAnnotation.class)は必要ないように見えます(少なくとも私がテストした5.4.0バージョンでは)。

補足事項
質問について:統合テストを作成するには、JUnit 5が最適ですか?私はそれが最初に検討すべきツールであるとは思いません(Cucumberとcoは統合テストにもっと具体的な価値と機能をもたらすことが多いです)いくつかの統合テストケースでは、JUnitフレームワークで十分です。つまり、この機能が存在することは朗報です。


4

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


3

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

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

org.junit.runners.Suite

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

これらは、機能テスト、統合テスト、またはシステムテストの作成に使用できます。

これにより、ユニットテストは特定の順序なしで(推奨どおり)そのままになり、そのように実行するかどうかに関係なく、全体像の一部としてテストを再利用できます。

単体テスト、統合テスト、システムテストで同じコードを再利用/継承します。データ駆動型、コミット駆動型、スイートとして実行する場合もあります。


2
2014年以降、この回答を完了する時間がありませんでしたか?;)
チャーリー

2

ここで私の解決策を参照してください:「Junit and java 7.」

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

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

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


私はあなたのブログ投稿を見ました(ロシア語で!)が、これはあまりにも複雑です。
Nicolas Barbulesco 2013

1
@NicolasBarbulesco私には2つのブログ(rusとeng)があります。実行順序に依存するテストを作成しないため、複雑すぎます。私の解決策は回避策ですが、実際の解決策はその依存関係を削除することです。
kornero 2013年

1
この投稿には実際の回答は含まれていません。リンクの他に、少なくとも基本的な説明を追加することを検討してください。
デフォルトのロケール


0

私はいくつかの回答を読み、ベストプラクティスではありませんが、テストを注文する最も簡単な方法と、JUnitがデフォルトでテストを実行する方法は、アルファベット順の昇順であることに同意します。

だから、あなたが望むアルファベット順にテストに名前を付けてください。また、テスト名はtestという単語で始まる必要があることに注意してください。数字に気をつけて

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

そう:

testA_MyFirstTest testC_ThirdTest testB_ATestThatRunsSecond


0

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


0

これは、目的の動作を生成できるJUnitの拡張機能です。https//github.com/aafuks/aaf-junit

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


0

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

これはこの質問に完全には関連していませんが、おそらく正しい問題をターゲットにするのに役立つかもしれません


0

次のコードのいずれかを使用できます。

@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 { ...}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.