jUnit4.xのスイート実行前後のフック


84

jUnit 4.4を使用してテストを実行し、一連の統合テストのセットアップとティアダウンを実行しようとしています。分解は確実に実行する必要があります。TestNGで他の問題が発生しているので、jUnitに移植することを検討しています。テストを実行する前、およびすべてのテストが完了した後、実行できるフックは何ですか?

注:ビルドにはMaven2を使用しています。Mavenのpre-post-integration-testフェーズを使用してみましたが、テストが失敗すると、Mavenが停止して実行されませんpost-integration-test。これは役に立ちません。


1
統合テストでは、surefireの代わりにmaven- failsafe -pluginを使用する必要があります。post-integration-testテストが失敗した場合、これはスキップされません。このwikiページも参照してください
クリスH.

最終的な実装を教えていただけますか?
vikramvi 2018

回答:


113

はい。テストスイートでのテストの前後に、セットアップメソッドとティアダウンメソッドを確実に実行できます。コードでデモンストレーションしましょう:

package com.test;

import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;

@RunWith(Suite.class)
@SuiteClasses({Test1.class, Test2.class})
public class TestSuite {

    @BeforeClass
    public static void setUp() {
        System.out.println("setting up");
    }

    @AfterClass
    public static void tearDown() {
        System.out.println("tearing down");
    }

}

したがって、Test1クラスは次のようになります。

package com.test;

import org.junit.Test;


public class Test1 {
    @Test
    public void test1() {
        System.out.println("test1");
    }

}

...そしてあなたはそれTest2が似ていると想像することができます。あなたが走った場合TestSuite、あなたは得るでしょう:

setting up
test1
test2
tearing down

したがって、セットアップ/ティアダウンは、それぞれすべてのテストの前と後にのみ実行されることがわかります。

落とし穴:これは、テストスイートを実行していて、Test1とTest2を個別のJUnitテストとして実行していない場合にのみ機能します。Mavenを使用しているとおっしゃいましたが、Mavenのsurefireプラグインは、スイートの一部ではなく、個別にテストを実行するのが好きです。この場合、各テストクラスが拡張するスーパークラスを作成することをお勧めします。スーパークラスには、注釈付きの@BeforeClassメソッドと@AfterClassメソッドが含まれます。上記の方法ほどきれいではありませんが、うまくいくと思います。

失敗したテストの問題については、失敗したテストでビルドが続行されるようにmaven.test.error.ignoreを設定できます。これは継続的な練習としてはお勧めできませんが、すべてのテストに合格するまで機能するはずです。詳細については、Mavenのsurefireのドキュメントを参照してください。


2
これは、maven-surefire-pluginにアクセスして、実行したいスイートを指すインクルードリストを作成すると完全に機能しました。
Jherico 2009年

2
JUnit 4.8.2の時点では、これはパラメーター化されたテストではうまく機能しません。スイートの@BeforeClassメソッドは、テストの@ Parameterized.Parametersメソッドのに実行され、スイートのセットアップへの依存を防ぎます。
anm 2011

私自身に応えて、@ Theoriesを使用する場合、@ DataPointsメソッドの呼び出しは、スイートの@BeforeClassのに呼び出されます。
anm 2011

18
ネクロで申し訳ありませんが、スーパークラスにBeforeClass / AfterClassを追加しても、期待どおりに機能しません。各テストクラスが完了した後も呼び出されます。これは後世のためです。
Subu Sankara Subramanian 2012

3
これはまだ有効なアプローチですか?SuiteClassesアノテーションでテストクラスのリストを列挙する必要性を回避するにはどうすればよいですか?
Burhan Ali

33

私の同僚は次のことを提案しました:カスタムRunListenerを使用して、testRunFinished()メソッドを実装できます:http://junit.sourceforge.net/javadoc/org/junit/runner/notification/RunListener.html#testRunFinished(org 。 junit.runner.Result)

:次のようにRunListenerを登録するには、単に確実なプラグインを設定 http://maven.apache.org/surefire/maven-surefire-plugin/examples/junit.htmlセクションには、「カスタムリスナーと記者の使用します」

この構成は、フェイルセーフプラグインでも選択する必要があります。このソリューションは、スイート、ルックアップテストクラス、またはこれらのいずれかを指定する必要がないため、優れています。これにより、Mavenはすべてのテストが終了するのを待って、魔法をかけることができます。


5
+1これは、Suitesクラスの面倒なメンテナンスなしで私が見た最初の使用可能なソリューションです!
Stefan Haberl 2013年


7

アノテーションを使用すると、次のようなことができます。

import org.junit.*;
import static org.junit.Assert.*;
import java.util.*;

class SomethingUnitTest {
    @BeforeClass
    public static void runBeforeClass()
    {

    }

    @AfterClass
    public static void runAfterClass()
    {  

    }

    @Before  
    public void setUp()
    {

    }

    @After
    public void tearDown()
    {

    }

    @Test
    public void testSomethingOrOther()
    {

    }

}

4
セットアップとティアダウンは、実行ごとに1回実行する必要があります。これは、すべてのテストが1つのクラスにある場合にのみ役立ちます。
sblundy 2008

3

ここでは、

  • JUnit4.5にアップグレードしました。
  • 動作するサービスを必要とする各テストクラスまたはメソッドにタグを付けるための注釈を作成しました。
  • サービスのセットアップとティアダウンを実装するための静的メソッドを含む各アノテーションのハンドラーを作成しました。
  • 通常のランナーを拡張してテスト上のアノテーションを見つけ、静的ハンドラーメソッドをテスト実行チェーンの適切なポイントに追加しました。

2

「注:ビルドにはmaven 2を使用しています。mavenの統合前および統合後のテストフェーズを使用してみましたが、テストが失敗すると、mavenは停止し、統合後のテストは実行されません。 、それは助けにはなりません。」

代わりにフェイルセーフプラグインを試すことができます。セットアップや中間段階のステータスに関係なく、クリーンアップが確実に行われるようにする機能があると思います。


はい、フェイルセーフプラグインを使用すると、特定のセットアップとティアダウンを指定できます。この質問が投稿された時点では、フェイルセーフは存在していなかったと思いますが。
Jason Axelson 2012

2

すべてのテストが「テクニカル」クラスを拡張し、同じパッケージに含まれている場合は、ちょっとしたトリックを行うことができます。

public class AbstractTest {
  private static int nbTests = listClassesIn(<package>).size();
  private static int curTest = 0;

  @BeforeClass
  public static void incCurTest() { curTest++; }

  @AfterClass
  public static void closeTestSuite() {
      if (curTest == nbTests) { /*cleaning*/ }             
  }
}

public class Test1 extends AbstractTest {
   @Test
   public void check() {}
}
public class Test2 extends AbstractTest {
   @Test
   public void check() {}
}

このソリューションには多くの欠点があることに注意してください。

  • パッケージのすべてのテストを実行する必要があります
  • 「技術的」クラスをサブクラス化する必要があります
  • サブクラス内で@BeforeClassと@AfterClassを使用することはできません
  • パッケージ内で1つのテストのみを実行すると、クリーニングは実行されません。
  • ..。

詳細情報:listClassesIn()=> Javaで特定のクラスのすべてのサブクラスを見つけるにはどうすればよいですか?


1
私自身のテストが示す限り、これは真実ではありません。埋め込みグラスフィッシュをクラス前に開始し、クラス後にシャットダウンするスーパークラスがあります。次に、そのスーパークラスから拡張する2つのクラスがあります。beforeclassは、各クラスで定義されたテストを実行する前に実行されます。
ジョナサン・モラレスベレス

0

私の知る限り、JUnitでこれを行うメカニズムはありませんが、Suiteをサブクラス化し、フックを提供するバージョンでrun()メソッドをオーバーライドしてみることができます。


0

maven-surefire-pluginは最初にSuiteクラスを実行せず、スイートクラスとテストクラスを同じように扱うため、以下のようにプラグインを構成して、スイートクラスのみを有効にし、すべてのテストを無効にすることができます。Suiteはすべてのテストを実行します。

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>2.5</version>
            <configuration>
                <includes>
                    <include>**/*Suite.java</include>
                </includes>
                <excludes>
                    <exclude>**/*Test.java</exclude>
                    <exclude>**/*Tests.java</exclude>
                </excludes>
            </configuration>
        </plugin>

0

必要な機能を取得するための唯一の方法は、次のようなことを行うことです。

import junit.framework.Test;  
import junit.framework.TestResult;  
import junit.framework.TestSuite;  

public class AllTests {  
    public static Test suite() {  
        TestSuite suite = new TestSuite("TestEverything");  
        //$JUnit-BEGIN$  
        suite.addTestSuite(TestOne.class);  
        suite.addTestSuite(TestTwo.class);  
        suite.addTestSuite(TestThree.class);  
        //$JUnit-END$  
     }  

     public static void main(String[] args)  
     {  
        AllTests test = new AllTests();  
        Test testCase = test.suite();  
        TestResult result = new TestResult();  
        setUp();  
        testCase.run(result);  
        tearDown();  
     }  
     public void setUp() {}  
     public void tearDown() {}  
} 

私はEclipseでこのようなものを使用しているので、その環境の外でどれほどポータブルかわかりません


3
これはJUnit3の例であり、OPはJUnit4を要求しましたが、一部のJUnit3ユーザーがこの質問を見つけた場合に備えて... JUnit3の場合は、main()メソッドを削除してsuite()メソッドを使用することをお勧めします。 TestSuiteをjunit.extensions.TestSetupのサブクラスでラップします。IDEで個々のテストクラスを実行することについてのジュリーの例と同じ警告がまだあります。
NamshubWriter 2010年

0

スイートを作成せず、すべてのテストクラスを一覧表示する必要がある場合は、リフレクションを使用してテストクラスの数を動的に検索し、基本クラス@AfterClassでカウントダウンして、ティアダウンを1回だけ実行できます。

public class BaseTestClass
{
    private static int testClassToRun = 0;

    // Counting the classes to run so that we can do the tear down only once
    static {
        try {
            Field field = ClassLoader.class.getDeclaredField("classes");
            field.setAccessible(true);

            @SuppressWarnings({ "unchecked", "rawtypes" })
            Vector<Class> classes = (Vector<Class>) field.get(BlockJUnit4ClassRunner.class.getClassLoader());
            for (Class<?> clazz : classes) {
                if (clazz.getName().endsWith("Test")) {
                    testClassToRun++;
                }
            }
        } catch (Exception ignore) {
        }
    }

    // Setup that needs to be done only once
    static {
        // one time set up
    }

    @AfterClass
    public static void baseTearDown() throws Exception
    {
        if (--testClassToRun == 0) {
            // one time clean up
        }
    }
}

静的ブロックの代わりに@BeforeClassを使用する場合は、ブールフラグを使用して、最初の呼び出しで1回だけリフレクションカウントとテストセットアップを実行することもできます。これが誰かに役立つことを願って、スイート内のすべてのクラスを列挙するよりも良い方法を見つけるのに午後がかかりました。

これで、このクラスをすべてのテストクラスに拡張するだけで済みます。すべてのテストに共通するものを提供する基本クラスがすでにあるので、これが私たちにとって最良のソリューションでした。

インスピレーションはこのSOの答えから来ています https://stackoverflow.com/a/37488620/5930242

このクラスをどこにでも拡張したくない場合は、この最後のSOの答えがあなたが望むことをするかもしれません。

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