web-dev-qa-db-ja.com

jUnit 4.xのSuite実行前および後のフック

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

注:ビルドにはmaven 2を使用しています。私はmavenのpre-post-integration-test段階ですが、テストが失敗すると、mavenは停止し、実行されませんpost-integration-test、これは役に立ちません。

81
sblundy

はい。テストスイートでのテストの前後に、確実にセットアップおよびティアダウンメソッドを実行できます。コードでデモンストレーションさせてください:

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

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

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

失敗したテストの問題については、maven.test.error.ignoreを設定して、失敗したテストでビルドを続行できます。これは継続的なプラクティスとしては推奨されませんが、すべてのテストに合格するまで機能するはずです。詳細については、 maven surefire documentation を参照してください。

111
Julie

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

RunListenerを登録するには、次のようにsurefireプラグインを設定するだけです。 http://maven.Apache.org/surefire/maven-surefire-plugin/examples/junit.html section「カスタムリスナーとレポーターの使用」

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

32
Martin Vysny
11
Tobogganski

注釈を使用すると、次のようなことができます。

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

    }

}
7
Jroc

ここで、私たち

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

すべてのテストが「技術的な」クラスを拡張し、同じパッケージ内にある場合、ちょっとしたトリックを行うことができます。

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で指定されたクラスのすべてのサブクラスを見つける方法

2
christophe blin

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

代わりにfailsafe-pluginを試すことができます。セットアップまたは中間段階のステータスに関係なくクリーンアップが行われるようにする機能があると思います

2
Binod Pant

スイートを作成せず、すべてのテストクラスを一覧表示する必要がない場合は、リフレクションを使用してテストクラスの数を動的に検索し、基本クラス@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 answer https://stackoverflow.com/a/37488620/5930242

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

0
FredBoutin

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

あなたが望む機能を得るために私が考える唯一の方法は、次のようなことをすることです

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でこのようなものを使用しているので、その環境の外でどれくらい移植性があるのか​​分かりません

0
Jroc

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

0
user15299