タイトルが言うように、私はEclipseを使用してJUnit 4.xテストを自動的に連続して数回実行する簡単な方法を探しています。
例としては、同じテストを10回続けて実行し、結果を報告します。
私たちはすでにこれを行うための複雑な方法を持っていますが、私が修正しようとしている不安定なテストが修正されたままであることを確認できるように、簡単な方法を探しています。
理想的なソリューションは、私が知らないEclipseプラグイン/設定/機能です。
タイトルが言うように、私はEclipseを使用してJUnit 4.xテストを自動的に連続して数回実行する簡単な方法を探しています。
例としては、同じテストを10回続けて実行し、結果を報告します。
私たちはすでにこれを行うための複雑な方法を持っていますが、私が修正しようとしている不安定なテストが修正されたままであることを確認できるように、簡単な方法を探しています。
理想的なソリューションは、私が知らないEclipseプラグイン/設定/機能です。
回答:
これを行う最も簡単な(少なくとも必要な新しいコードの量として)方法は、テストをパラメーター化されたテストとして実行することです(注釈を付け、@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はランナーのレイヤーをサポートしていません。それは他のランナーをつなぐランナーです。
IntelliJを使用すると、テスト構成からこれを実行できます。このウィンドウを開いたら、必要な回数だけテストを実行することを選択できます。
テストを実行すると、intellijは、指定した回数だけ選択したすべてのテストを実行します。
Springのリピートアノテーションは、このような場合に役立つことがわかりました。
@Repeat(value = 10)
最新(Spring Framework 4.3.11.RELEASE API)ドキュメント:
以下のリソースに触発されました:
@Repeat
次のように注釈を作成して使用します。
public class MyTestClass {
@Rule
public RepeatRule repeatRule = new RepeatRule();
@Test
@Repeat(10)
public void testMyCode() {
//your test code goes here
}
}
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;
}
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;
}
}
このソリューションを@RunWith(PowerMockRunner.class)
で使用するには、Powermock 1.6.5(パッチを含む)に更新する必要があります。
JUnit 5では、@ RepeatedTestアノテーションを使用してこれを解決できました。
@RepeatedTest(10)
public void testMyCode() {
//your test code goes here
}
@Test
アノテーションはとともに使用しないでください@RepeatedTest
。
何か問題があります:
@Test
void itWorks() {
// stuff
}
@Test
void itWorksRepeatably() {
for (int i = 0; i < 10; i++) {
itWorks();
}
}
値の各配列をテストする場合とは異なり、どの実行が失敗したかは特に気にする必要はありません。
コードで実行できることを構成や注釈で行う必要はありません。
@Before
する前に手動で注釈付きメソッドを呼び出すことと一緒itWorks()
です。
これは私にとってははるかに簡単に機能します。
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;
}
}
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テストに合格しました」
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
)、testCounter
99になります。
この種のテストを実行できるモジュールを作成します。しかし、それはリピートだけではありません。しかし、一部のコードがスレッドセーフであることを保証します。
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");
}
}
これはオープンソースプロジェクトです。自由に改善してください。
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
}
}
}
}