同じjunitテストを繰り返し実行する簡単な方法は?


121

タイトルが言うように、私はEclipseを使用してJUnit 4.xテストを自動的に連続して数回実行する簡単な方法を探しています。

例としては、同じテストを10回続けて実行し、結果を報告します。

私たちはすでにこれを行うための複雑な方法を持っていますが、私が修正しようとしている不安定なテストが修正されたままであることを確認できるように、簡単な方法を探しています。

理想的なソリューションは、私が知らないEclipseプラグイン/設定/機能です。


5
なぜこれをしたいのか、私はとても興味があります。
Buhb

私は大きなブラックボックステストを実行していますが、小さな変更を加えており、これが以前の不安定なテストの安定性にどのように影響したかを確認したいと考えています。
Stefan Thyberg、2009

それは確かに、失敗するまで実行したいということを除けば、私は何度も実行したいだけで、得られる答えに影響を与える可能性があります。
Stefan Thyberg、2010年

4
TestNGに反対ですか?そうでない場合は、@ Test(invocationCount = 10)を使用するだけでよいので、それだけです。
ロバートマサイオリ

1
私はTestNGに対して「反対」ではなく、そのプロジェクトでそれを使用していませんでした。
Stefan Thyberg、2011

回答:


123

これを行う最も簡単な(少なくとも必要な新しいコードの量として)方法は、テストをパラメーター化されたテストとして実行することです(注釈を付け、@RunWith(Parameterized.class)10個の空のパラメーターを提供するメソッドを追加します)。このようにして、フレームワークはテストを10回実行します。

このテストは、クラス内の唯一のテストである必要があります。または、すべてのテストメソッドをクラスで10回実行する必要があります。

次に例を示します。

@RunWith(Parameterized.class)
public class RunTenTimes {

    @Parameterized.Parameters
    public static Object[][] data() {
        return new Object[10][0];
    }

    public RunTenTimes() {
    }

    @Test
    public void runsTenTimes() {
        System.out.println("run");
    }
}

上記を使用すると、パラメーターなしのコンストラクターでそれを実行することも可能ですが、フレームワークの作成者がそれを意図していたのか、それとも将来的に機能しなくなるのかはわかりません。

独自のランナーを実装する場合は、ランナーにテストを10回実行させることができます。サードパーティのランナーを使用している場合、4.7では、新しい@Ruleアノテーションを使用してMethodRuleインターフェースを実装し、ステートメントを受け取ってforループで10回実行することができます。このアプローチの現在の不利な点はそれで@Beforeあり、@After一度しか実行されません。これは次のバージョンのJUnitで変更される可能性があります(はの@Before後に実行され@Ruleます)が、オブジェクトの同じインスタンス(Parameterizedランナーには当てはまらないもの)を操作することになります。これは、クラスを実行しているランナーが@Rule注釈を正しく認識することを前提としています。これは、JUnitランナーに委任されている場合にのみ当てはまります。

@Ruleアノテーションを認識しないカスタムランナーを使用して実行している場合、そのランナーに適切に委譲してそれを10回実行する独自のランナーを作成する必要があります。

これを解決する方法は他にもある(Theoriesランナーなど)が、すべてランナーが必要であることに注意してください。残念ながら、現在JUnitはランナーのレイヤーをサポートしていません。それは他のランナーをつなぐランナーです。


2
残念ながら、私はすでに別のランナーで@RunWithを実行していますが、それ以外の場合はこれが理想的なソリューションでした。
Stefan Thyberg、2009

はい、これは私が望んでいる解決策であり、ほとんどの人にとって最良の解決策なので、先に進んで答えを受け入れます。
Stefan Thyberg、2009年

代わりの、おそらく
ハッキング

素敵な解決策!dataメソッドがIterable of Arraysを返す必要があることを伝える例外が発生しました。私はそれに応じて修正しました:@ Parameterized.Parameters public static Iterable <Object []> data(){return Arrays.asList(new Object [20] [0]); }
nadre

1
JUnit 5のこの回答にリンクしていただけませんか?JUnit 5で追加されたリクエストされた機能について説明します
Marcono1234 '22

100

IntelliJを使用すると、テスト構成からこれを実行できます。このウィンドウを開いたら、必要な回数だけテストを実行することを選択できます。

ここに画像の説明を入力してください

テストを実行すると、intellijは、指定した回数だけ選択したすべてのテストを実行します。

624テストを10回実行する例: ここに画像の説明を入力してください


4
これは完璧です。これを実行するための日食の方法を指定できる場合、それはOPの質問の要点に答えます
khal

実際のロジックまたは要件をホストするために特定のツールに依存することは、アンチパターンです。
ミカエル

1
@MickaelテストをN回繰り返すことは、通常、テストの要件ではありません。実際、テストは確定的である必要があります。そのため、何回繰り返されても、常に同じ結果が得られるはずです。あなたが話しているアンチパターンを説明できますか?
smac89

テストを繰り返すことが1人の開発者にとって有用であった場合、それは他の人にとっても有用である可能性があります。したがって、テストランタイムとコードが繰り返しを可能にするロジックをホストできる場合は、労力とソリューションを因数分解でき、貢献者が同じ結果でツールを使用できるようになるため、それを優先する必要があります。再利用可能なロジックをコード内に配置できるときにIDE /開発者領域に配置することは、一種の欠けている分解です。
ミカエル

68

Springのリピートアノテーションは、このような場合に役立つことがわかりました。

@Repeat(value = 10)

最新(Spring Framework 4.3.11.RELEASE API)ドキュメント:


46
テストフレームワークの変更は、簡単な方法とは言えません。
Stefan Thyberg、2009

3
テストフレームワークを変更する必要はありません-JUnitで正常に動作します。主な欠点は、JUnitがまだそれを単一のテストと見なしていることです。したがって、最初にブレークすると、実行が停止します。ただし、まだSpringを使用していない場合は、おそらく望んでいる方法ではありません...
tveon

動作しないようです(Spring 4.3.6経由のSpring 4.3.6)
David Tonhofer

春のブート2.1.6とJUnit 5で私のために動作しません
jo-

春のブーツ2で完全に動作します。ポスターの「春の単体テスト」リンクに従って、@ RunWith(SpringRunner :: class)を追加することを忘れないでください。
Agoston Horvath

33

以下のリソースに触発されました:

@Repeat次のように注釈を作成して使用します。

public class MyTestClass {

    @Rule
    public RepeatRule repeatRule = new RepeatRule();

    @Test
    @Repeat(10)
    public void testMyCode() {
        //your test code goes here
    }
}

Repeat.java

import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.METHOD;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention( RetentionPolicy.RUNTIME )
@Target({ METHOD, ANNOTATION_TYPE })
public @interface Repeat {
    int value() default 1;
}

RepeatRule.java

import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;

public class RepeatRule implements TestRule {

    private static class RepeatStatement extends Statement {
        private final Statement statement;
        private final int repeat;    

        public RepeatStatement(Statement statement, int repeat) {
            this.statement = statement;
            this.repeat = repeat;
        }

        @Override
        public void evaluate() throws Throwable {
            for (int i = 0; i < repeat; i++) {
                statement.evaluate();
            }
        }

    }

    @Override
    public Statement apply(Statement statement, Description description) {
        Statement result = statement;
        Repeat repeat = description.getAnnotation(Repeat.class);
        if (repeat != null) {
            int times = repeat.value();
            result = new RepeatStatement(statement, times);
        }
        return result;
    }
}

PowerMock

このソリューションを@RunWith(PowerMockRunner.class)で使用するには、Powermock 1.6.5パッチを含む)に更新する必要があります。


はい。テストをどのように実行していますか?
R.

私は日食を使っていません。多分あなたはjunut 4テストランナーを使っていませんか?(ドキュメント「テスト構成のカスタマイズ」を参照)
R. Oosterholt 2015

29

JUnit 5では、@ RepeatedTestアノテーションを使用してこれを解決できました。

@RepeatedTest(10)
public void testMyCode() {
    //your test code goes here
}

@Testアノテーションはとともに使用しないでください@RepeatedTest


非常に有望に聞こえますが、リリースバージョンはまだありません。
9ilsdx 9rvj 0lo 2017

1
JUnit 5は2週間前にGAになりました。
mkobit 2017年

11

何か問題があります:

@Test
void itWorks() {
    // stuff
}

@Test
void itWorksRepeatably() {
    for (int i = 0; i < 10; i++) {
        itWorks();
    }
}

値の各配列をテストする場合とは異なり、どの実行が失敗したかは特に気にする必要はありません。

コードで実行できることを構成や注釈で行う必要はありません。


2
通常の単体テストとしていくつかのテストを実行し、それぞれのトレースとステータスを取得したいと思います。
Stefan Thyberg、2009年

24
この場合、 "@ Before"と "@After"は実行されません
Bogdan

3
これは 、私の問題を解決@Beforeする前に手動で注釈付きメソッドを呼び出すことと一緒itWorks()です。
ジョアン・ネベス

DRYの概念を知っていますか?en.wikipedia.org/wiki/Don%27t_repeat_yourselfループをどこにでもコピーアンドペーストするのではなく、いくつかの設定を行うことをお勧めします。
キキワ2016年

この回答の編集キューがいっぱいです。したがって、私はそれをコメントに入れます。JUnit4の場合、テストはパブリックである必要があります。
Richard Jessop

7

これは私にとってははるかに簡単に機能します。

public class RepeatTests extends TestCase {

    public static Test suite() {
        TestSuite suite = new TestSuite(RepeatTests.class.getName());

        for (int i = 0; i < 10; i++) {              
        suite.addTestSuite(YourTest.class);             
        }

        return suite;
    }
}

別のフレームワークを使用せず、実際にはJUnit 3(androidには重要)で動作する素晴らしい
Vladimir Ivanov '27

1
JUnit4を使用した実装は、ランナーで実行できます。 public class RepeatRunner extends BlockJUnit4ClassRunner { public RepeatRunner(Class klass) throws InitializationError { super(klass); } @Override public void run(final RunNotifier notifier) { for (int i = 0; i < 10; i++) { super.run(notifier); } } }少なくともEclipse JUnitプラグインでは、次のような結果が得られます。「10/1テストに合格しました」
Peter Wippermann

7

tempus-fugitライブラリーに断続的な注釈があり、JUnit 4.7と連携し@Ruleてテストを数回または@RunWithます。

例えば、

@RunWith(IntermittentTestRunner.class)
public class IntermittentTestRunnerTest {

   private static int testCounter = 0;

   @Test
   @Intermittent(repition = 99)
   public void annotatedTest() {
      testCounter++;
   }
}

テストが実行された後(のIntermittentTestRunnerを使用@RunWith)、testCounter99になります。


ええ、これは同じ問題です。すでに別のランナーを使用しているため、このランナーは使用できませんが、良い考えです。
Stefan Thyberg、2010年

ええ、RunWithで同じ問題が発生しています...少し丸めるためにtempus-fugitを微調整したので、繰り返し実行したい場合は、ランナーではなく@Ruleを使用できます。断続的ではなく@Repeatingでマークアップします。ただし、ルールバージョンは@ Before / @ Aftersを実行しません。詳細については、tempus-fugit.googlecode.com / svn / site / documentation / (スクロールしてロード/ソークテスト)を参照してください。
Toby

0

この種のテストを実行できるモジュールを作成します。しかし、それはリピートだけではありません。しかし、一部のコードがスレッドセーフであることを保証します。

https://github.com/anderson-marques/concurrent-testing

Maven依存関係:

<dependency>
    <groupId>org.lite</groupId>
    <artifactId>concurrent-testing</artifactId>
    <version>1.0.0</version>
</dependency>

使用例:

package org.lite.concurrent.testing;

import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import ConcurrentTest;
import ConcurrentTestsRule;

/**
 * Concurrent tests examples
 */
public class ExampleTest {

    /**
     * Create a new TestRule that will be applied to all tests
     */
    @Rule
    public ConcurrentTestsRule ct = ConcurrentTestsRule.silentTests();

    /**
     * Tests using 10 threads and make 20 requests. This means until 10 simultaneous requests.
     */
    @Test
    @ConcurrentTest(requests = 20, threads = 10)
    public void testConcurrentExecutionSuccess(){
        Assert.assertTrue(true);
    }

    /**
     * Tests using 10 threads and make 20 requests. This means until 10 simultaneous requests.
     */
    @Test
    @ConcurrentTest(requests = 200, threads = 10, timeoutMillis = 100)
    public void testConcurrentExecutionSuccessWaitOnly100Millissecond(){
    }

    @Test(expected = RuntimeException.class)
    @ConcurrentTest(requests = 3)
    public void testConcurrentExecutionFail(){
        throw new RuntimeException("Fail");
    }
}

これはオープンソースプロジェクトです。自由に改善してください。


0

JUnitテストをメインメソッドから実行し、必要な回数だけ繰り返すことができます。

package tests;

import static org.junit.Assert.*;

import org.junit.Test;
import org.junit.runner.Result;

public class RepeatedTest {

    @Test
    public void test() {
        fail("Not yet implemented");
    }

    public static void main(String args[]) {

        boolean runForever = true;

        while (runForever) {
            Result result = org.junit.runner.JUnitCore.runClasses(RepeatedTest.class);

            if (result.getFailureCount() > 0) {
                runForever = false;
               //Do something with the result object

            }
        }

    }

}

0

これは本質的に、YishaiがKotlinで書き直した上記の回答です。

@RunWith(Parameterized::class)
class MyTest {

    companion object {

        private const val numberOfTests = 200

        @JvmStatic
        @Parameterized.Parameters
        fun data(): Array<Array<Any?>> = Array(numberOfTests) { arrayOfNulls<Any?>(0) }
    }

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