Javaアプリ、テスト用のJunit、フェイルセーフおよびシュアファイアプラグインを使用しています。2000以上の統合テストがあります。テストの実行速度を上げるために、フェイルセーフjvmforkを使用してテストを実行しますパラレル。いくつかの重いテストクラスがあり、それらは通常、テスト実行の最後に実行され、CI検証プロセスが遅くなります。filesaferunorder:balancedは私にとっては良いオプションですが、jvmforkが原因で使用できません。テストクラスの名前を変更するか、別のパッケージに移動してそれを実行することはオプションではありません。検証プロセスの開始時に、遅いテストクラスを実行するにはどうすればよいですか?
推奨事項を提供する前に、すべてを要約しましょう。
現時点では、迅速なフィードバックの取得に問題はないと確信しています。ただし、統合テストをより速く実行したいのです。私は次の解決策をお勧めします:
私はさまざまなプロジェクト(CIビルドが48時間実行されていたものもある)を扱っており、最初の3ステップで十分です(クレイジーなケースでも)。手順4は、適切なテストを行う必要があることはめったにありません。ステップ#5は非常に特定の状況用です。
問題はプロセスにあるため、私の推奨事項はツールではなくプロセスに関連していることがわかります。
たいていの場合、根本原因を無視してツールを調整しようとします(この場合はMaven)。彼らは化粧品の改善を得ますが、作成されたソリューションの維持費は高くなります。
私は試してみた答えの組み合わせを与えました:
2番目の答えは、これらの classes
プロジェクトに基づいています github
プロジェクトは、BSD-2ライセンスの下で利用できます。
私はいくつかのテストクラスを定義しました:
public class LongRunningTest {
@Test
public void test() {
System.out.println(Thread.currentThread().getName() + ":\tlong test - started");
long time = System.currentTimeMillis();
do {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
} while(System.currentTimeMillis() - time < 1000);
System.out.println(Thread.currentThread().getName() + ":\tlong test - done");
}
}
@Concurrent
public class FastRunningTest1 {
@Test
public void test1() {
try {
Thread.sleep(250);
} catch (InterruptedException e) {
}
System.out.println(Thread.currentThread().getName() + ":\tfrt1-test1 - done");
}
// +7 more repetions of the same method
}
次に、テストスイートを定義しました。
(FastRunningTest2は、出力が調整された最初のクラスのコピーです)
@SuiteClasses({LongRunningTest.class, LongRunningTest.class})
@RunWith(Suite.class)
public class SuiteOne {}
@SuiteClasses({FastRunningTest1.class, FastRunningTest2.class})
@RunWith(Suite.class)
public class SuiteTwo {}
@SuiteClasses({SuiteOne.class, SuiteTwo.class})
@RunWith(ConcurrentSuite.class)
public class TopLevelSuite {}
TopLevelSuite
を実行すると、次の出力が得られます。
TopLevelSuite-1-thread-1: long test - started FastRunningTest1-1-thread-4: frt1-test4 - done FastRunningTest1-1-thread-2: frt1-test2 - done FastRunningTest1-1-thread-1: frt1-test1 - done FastRunningTest1-1-thread-3: frt1-test3 - done FastRunningTest1-1-thread-5: frt1-test5 - done FastRunningTest1-1-thread-3: frt1-test6 - done FastRunningTest1-1-thread-1: frt1-test8 - done FastRunningTest1-1-thread-5: frt1-test7 - done FastRunningTest2-2-thread-1: frt2-test1 - done FastRunningTest2-2-thread-2: frt2-test2 - done FastRunningTest2-2-thread-5: frt2-test5 - done FastRunningTest2-2-thread-3: frt2-test3 - done FastRunningTest2-2-thread-4: frt2-test4 - done TopLevelSuite-1-thread-1: long test - done TopLevelSuite-1-thread-1: long test - started FastRunningTest2-2-thread-5: frt2-test8 - done FastRunningTest2-2-thread-2: frt2-test6 - done FastRunningTest2-2-thread-1: frt2-test7 - done TopLevelSuite-1-thread-1: long test - done
これは基本的に、LongRunningTest
がFastRunningTests
と並行して実行されることを示しています。 Concurrent
アノテーションで定義された並列実行に使用されるスレッドのデフォルト値は5
であり、FastRunningTests
の並列実行の出力で確認できます。
欠点は、これらのThreads
がFastRunningTest1
とFastRunningTest2
の間で共有されないことです。
この動作は、やりたいことを「ある程度」実行できることを示しています(そのため、現在の設定でそれが機能するかどうかは別の問題です)。
これが実際に努力する価値があるかどうかもわかりませんが、
TestSuites
を手動で準備する必要があるため(またはそれらを自動生成するものを記述する)threads
を使って)これは基本的に、クラスの実行順序を定義して並列実行をトリガーできることを示しているため、プロセス全体で1つのThreadPool
のみを使用することも可能です(ただし、その意味はわかりません)そののだろう)。
全体の概念はThreadPoolExecutorに基づいているため、長期実行タスクに高い優先順位を与えるPriorityBlockingQueue
を使用すると、長期実行テストを最初に実行する理想的な結果に近づきます。
もう少し実験して、独自のカスタムスイートランナーとjunitランナーを実装しました。背後にあるアイデアは、JUnitRunnerに、単一のThreadPoolExecutor
によって処理されるキューにテストを送信させることです。 RunnerScheduler#finish
メソッドにブロッキング操作を実装しなかったので、実行が開始される前にすべてのクラスのテストがキューに渡されるという解決策になりました。 (より多くのテストクラスとメソッドが含まれている場合、それは異なって見えるかもしれません).
少なくとも、本当に必要な場合は、このレベルでjunitをいじることができるということを証明します。
私のpocのコードは少し面倒でここに置くのに時間がかかりますが、誰かが興味があればそれをgithubプロジェクトにプッシュできます。
プロジェクトでは、いくつかのマーカーインターフェイス(例
public interface SlowTestsCategory {}
)
遅いテストのテストクラスで、JUnitの@Categoryアノテーションに挿入します。
@Category(SlowTestsCategory.class)
その後、Gradleがいくつかの特別なタスクを作成して、カテゴリ別またはいくつかのカテゴリ別にカスタムオーダーでテストを実行しました。
task unitTest(type: Test) {
description = 'description.'
group = 'groupName'
useJUnit {
includeCategories 'package.SlowTestsCategory'
excludeCategories 'package.ExcludedCategory'
}
}
このソリューションはGradleによって提供されますが、おそらく役立つでしょう。
Junit 5のアノテーションを使用して、使用するテスト順序を設定できます。
Junit 5のユーザーガイドから: https://junit.org/junit5/docs/current/user-guide/#writing-tests-test-execution-order
import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
@TestMethodOrder(OrderAnnotation.class)
class OrderedTestsDemo {
@Test
@Order(1)
void nullValues() {
// perform assertions against null values
}
@Test
@Order(2)
void emptyValues() {
// perform assertions against empty values
}
@Test
@Order(3)
void validValues() {
// perform assertions against valid values
}
}
Junit5へのアップグレードはかなり簡単に行うことができ、投稿の冒頭にあるリンク上のドキュメントには、必要なすべての情報が含まれています。