Mavenビルドでjunitテストを並行して実行していますか?


110

私はJUnit 4.4とMavenを使用していますが、長時間実行される統合テストが多数あります。

テストスイートの並列化に関しては、単一のテストクラスで各テストメソッドを並行して実行できるいくつかのソリューションがあります。しかし、これらはすべて、何らかの方法でテストを変更する必要があります。

XスレッドでXの異なるテストクラスを並行して実行する方が、はるかにクリーンなソリューションになると思います。私は何百ものテストを持っているので、個々のテストクラスをスレッド化することはあまり気にしません。

これを行う方法はありますか?

回答:


75

mavenプラグインを使用する:

<build>
    <plugins>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.7.1</version>
        <configuration>
            <parallel>classes</parallel>
            <threadCount>5</threadCount>
        </configuration>
    </plugin>
    </plugins>
</build>

12
<parallel>は、Junit 4.7以降を使用している場合、実際には確実にサポートされます。surefireガイド
jontejj

42

junit 4.7以降、TestNGを使用せずにテストを並行して実行できるようになりました。実際には4.6以降で可能ですが、4.7でいくつかの修正が行われ、実行可能なオプションになっています。また、ここで読むことができる春で並列テストを実行することもできます


1
リンクされたページには、「ほとんどのデュアルコアソリューションの場合、並列スレッドで実行することは、現在、非スレッドで実行するよりも速くなることは決してない」とあります。それはまだ事実ですか?
Raedwald

2
私はあなたのテストがIOを実行するならば、彼らはまだ利益があると思います。たとえば、単体テストが統合テストに似ていてデータベースにヒットする場合は、並行して実行するとスピードが向上します。
Dave、

@Raedwald 短い非ioバインドの単体テストに期待しすぎないでください。新しいバージョンのsurefireも、投稿で説明されている2.5よりも優れており、効率もよいため、わずかに優れた結果が得られる場合があります。
krosenvold

3
あなたはそれが可能であると述べていますが、その方法の説明へのリンクを含めることができますか?あなたの2番目のリンクは、私はに興味がない、「春との」ためのものです。
コーリーケンドール

@krosenvoldリンク?組み込みのソリューションを見つけるのに苦労しています。
Ilan Biala

10

JUnitの実験的なParallelComputerランナーに触発されて、私は自分のParallelSuiteおよびParallelParameterizedランナーを構築しました。これらのランナーを使用すると、テストスイートとパラメーター化されたテストを簡単に並列化できます。

ParallelSuite.java

public class ParallelSuite extends Suite {

    public ParallelSuite(Class<?> klass, RunnerBuilder builder) throws InitializationError {

        super(klass, builder);

        setScheduler(new RunnerScheduler() {

            private final ExecutorService service = Executors.newFixedThreadPool(4);

            public void schedule(Runnable childStatement) {
                service.submit(childStatement);
            }

            public void finished() {
                try {
                    service.shutdown();
                    service.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
                } catch (InterruptedException e) {
                    e.printStackTrace(System.err);
                }
            }
        });
    }
}

ParallelParameterized.java

public class ParallelParameterized extends Parameterized {

    public ParallelParameterized(Class<?> arg0) throws Throwable {

        super(arg0);

        setScheduler(new RunnerScheduler() {

            private final ExecutorService service = Executors.newFixedThreadPool(8);

            public void schedule(Runnable childStatement) {
                service.submit(childStatement);
            }

            public void finished() {
                try {
                    service.shutdown();
                    service.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
                } catch (InterruptedException e) {
                    e.printStackTrace(System.err);
                }
            }
        });
    }
}

使い方は簡単です。@RunWithアノテーションの値をこれらのParallel *クラスのいずれかに変更するだけです。

@RunWith(ParallelSuite.class)
@SuiteClasses({ATest.class, BTest.class, CTest.class})
public class ABCSuite {}

5

tempus-fugitは同様のものを提供しています。詳細についてはドキュメントを確認してください。JUnit 4.7に依存しており、テストをマークするだけです@RunWith(ConcurrentTestRunner)です。

乾杯


3

オープンソースライブラリをチェックアウトできます-Test Load Balancerます。それはまさにあなたが求めるものを実行します-異なるテストクラスを並行して実行します。これはant-junitレベルで統合されるため、いずれにしてもテストを変更する必要はありません。私は図書館の著者の一人です。

また、プロセスレベルのサンドボックスが必要になる場合があるため、スレッドで実行しないことを検討してください。たとえば、統合テストでDBを使用している場合、別のテストが別のスレッドにデータを追加したため、1つのテストが失敗することは望ましくありません。ほとんどの場合、テストはこれを考慮して書かれていません。

最後に、これまでどのようにこの問題を解決しましたか?


2

TestNGはそれを行うことができます(これが私の最初の反射でした-それからあなたはすでにたくさんのテストケースを持っているのを見ました)。

JUnitについては、parallel-junitを参照しください。


3
残念ながら、これは私が尋ねている質問に対する答えではありません。parallel-junitは、単一のテストクラス内でのみ実行されます。TestNGも単一クラス内でのみ実行され、私のテストはTestNGテストではありません。
krosenvold 2009年

@PlatinumAzure:リンクを更新しました。このプロジェクトがどのように維持されているのかわかりません。最近、別の質問がいくつかのマシンでjunitテストの実行分散するように求められました。
フィランテ

2

Junit自体が提供するParallelComputerを使用して、テストを並行して実行できます。ここにあなたが始めるための小さなスニペットがあります。

Class[] cls = { TestCase1.class, TestCase2.class };
Result result = JUnitCore.runClasses(ParallelComputer.classes(), cls);
List<Failure> failures = result.getFailures();

Mavenや他のビルド管理ツールに依存しないため、コードからテストを実行する必要がある場合に役立ちます。

これにより、すべてのテストケースが並行して実行されます。異なるテストケース間に依存関係がある場合は、誤検知が発生する可能性があります。いずれにしても、相互依存テストはすべきではありません。


0

別の選択肢:新しい並列junitランナーおよびmavenプラグインであるPunner。コードを変更する必要はありません。コードをpom.xmlにコピーしてください:

<!-- Disable default surefire based testing -->
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-surefire-plugin</artifactId>
  <version>2.20</version>
  <configuration>
    <skip>true</skip>
  </configuration>
</plugin>

<plugin>
  <groupId>com.github.marks-yag</groupId>
  <artifactId>punner-maven-plugin</artifactId>
  <version>${version}</version>
  <configuration>
  </configuration>
  <executions>
    <execution>
      <id>test</id>
      <phase>test</phase>
      <goals>
        <goal>test</goal>
      </goals>
    </execution>
  </executions>
</plugin>

Punnerは、テストメソッドを並行して実行し、テスト出力を個別に保持してクリーンにすることができます。

Punnerは、次のようにmvnコンソールの出力を減らします。

[INFO] --- punner-maven-plugin:0.9.13:test (test) @ ipc ---
[INFO] Punner report directory: /Users/guile/workspace/ipc/target/punner-reports
[INFO]
[INFO] com.github.yag.ipc.IPCTest.testConnectionHandler.............. PASSED
[INFO] com.github.yag.ipc.IPCTest.testSequence....................... PASSED
[INFO] com.github.yag.ipc.IPCTest.testPartialContent................. PASSED
[INFO] com.github.yag.ipc.IPCTest.testResponseContent................ PASSED
[INFO] com.github.yag.ipc.IPCTest.testPingPong....................... PASSED
[INFO] com.github.yag.ipc.IPCTest.testServerClose.................... PASSED
[INFO] com.github.yag.ipc.IPCTest.testServerSideHeartbeatTimeout..... PASSED
[INFO] com.github.yag.ipc.IPCTest.testClientSideHeartbeatTimeout..... PASSED
[INFO] com.github.yag.ipc.IPCTest.testClientSideHeartbeat............ PASSED
[INFO] com.github.yag.ipc.IPCTest.testClientReconnect................ PASSED
[INFO]
[INFO] Tests run: 10, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 10.952 sec, Time saved: 25.919 sec.

Punnerは確実に互換性のある出力を生成します。レポートディレクトリから生のログデータとマークダウン形式のレポートを取得することもできます。

  ipc git:(develop) ll target/punner-reports
total 104
-rw-r--r--   1 guile  staff    11K Oct 15 23:07 TEST-com.github.yag.ipc.IPCTest.xml
-rw-r--r--   1 guile  staff   298B Oct 15 23:07 com.github.yag.ipc.IPCTest.txt
drwxr-xr-x  12 guile  staff   384B Oct  8 00:50 logs
-rw-r--r--   1 guile  staff    33K Oct 15 23:07 report.md

Punnerは私の個人的なプロジェクトです。Punnerを作成して、IPCフレームワーク、きめの細かいロック、ジャーナルサービス、分散ワークフローエンジンなど、他のいくつかのプロジェクトの単体テストフェーズを高速化しました。これにより、待ち時間を大幅に節約できました。

Punnerはまだいくつかの高度な機能をサポートしていません。試してみて、フィードバックをいただければ幸いです。


-3

テストをすぐにTestNgテストに変更できます(インポートを変更するだけです)。TestNGは並列テストに最適です。


-3

テストを計算グリッド全体に分散して実行できるようにするGridgainを試すことができます。


1
私はGridGainソリューションを試してみましたが、2つの大きな問題がありました。まず、GridGainがグリッドタスクのクラスパスから除外するようにGridGainに指示する必要があります。たとえば、Springや多くのApache Commonsのものなど、GridGainが使用するものもすべて除外します。第2に、ネットワークのクラスローディングは素晴らしいアイデアですが、クラスパスを検索したいライブラリ(たとえば、Spring
Graham Lea
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.