1. 概要

JUnit は、Javaエコシステムで最も人気のある単体テストフレームワークの1つです。 JUnit 5バージョンには、 Java 8以降の新機能をサポートし、さまざまなスタイルのテストを可能にすることを目的とした、多くのエキサイティングなイノベーションが含まれています。

2. Mavenの依存関係

JUnit5.x.0のセットアップは非常に簡単です。 pom.xmlに次の依存関係を追加する必要があります。

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-engine</artifactId>
    <version>5.8.1</version>
    <scope>test</scope>
</dependency>

さらに、EclipseのJUnitプラットフォームとIntelliJでユニットテストを実行するための直接サポートが追加されました。 もちろん、Mavenテストの目標を使用してテストを実行することもできます。

一方、IntelliJはデフォルトでJUnit5をサポートしています。 したがって、IntelliJでJUnit5を実行するのは非常に簡単です。 右クリック–>実行、またはCtrl-Shift-F10を押すだけです。

このバージョンが機能するにはJava8が必要であることに注意してください

3. 建築

JUnit 5は、3つの異なるサブプロジェクトからのいくつかの異なるモジュールで構成されています。

3.1. JUnitプラットフォーム

プラットフォームは、JVMでテストフレームワークを起動する役割を果たします。 ビルドツールなど、JUnitとそのクライアント間の安定した強力なインターフェイスを定義します。

このプラットフォームは、クライアントをJUnitと簡単に統合して、テストを検出して実行します。

また、JUnitプラットフォームで実行されるテストフレームワークを開発するための TestEngineAPIも定義します。 カスタムTestEngineを実装することで、サードパーティのテストライブラリをJUnitに直接プラグインできます。

3.2. JUnit Jupiter

このモジュールには、JUnit5でテストを作成するための新しいプログラミングモデルと拡張モデルが含まれています。 JUnit4と比較した新しいアノテーションは次のとおりです。

  • @TestFactory –動的テストのテストファクトリであるメソッドを示します
  • @DisplayName –テストクラスまたはテストメソッドのカスタム表示名を定義します
  • @Nested –注釈付きクラスがネストされた非静的テストクラスであることを示します
  • @Tag –フィルタリングテスト用のタグを宣言します
  • @ExtendWith –カスタム拡張機能を登録します
  • @BeforeEach – は、注釈付きメソッドが各テストメソッドの前に実行されることを示します(以前の @Before
  • @AfterEach –注釈付きメソッドが各テストメソッドの後に実行されることを示します(以前は @After
  • @BeforeAll –注釈付きメソッドが、現在のクラス(以前の @BeforeClass )のすべてのテストメソッドの前に実行されることを示します。
  • @AfterAll –注釈付きメソッドが現在のクラス(以前の @AfterClass )のすべてのテストメソッドの後に実行されることを示します
  • @Disable –テストクラスまたはメソッドを無効にします(以前は @Ignore

3.3. JUnit Vintage

JUnit Vintageは、JUnit5プラットフォームでのJUnit3およびJUnit4に基づくテストの実行をサポートします。

4. 基本的な注釈

新しい注釈について説明するために、このセクションを実行を担当する次のグループに分割しました:テスト前、テスト中(オプション)、およびテスト後:

4.1. @BeforeAllおよび@BeforeEach

以下は、メインのテストケースの前に実行される単純なコードの例です。

@BeforeAll
static void setup() {
    log.info("@BeforeAll - executes once before all test methods in this class");
}

@BeforeEach
void init() {
    log.info("@BeforeEach - executes before each test method in this class");
}

@BeforeAll アノテーションが付いたメソッドは静的である必要があることに注意することが重要です。そうしないと、コードがコンパイルされません。

4.2. @DisplayNameおよび@Disabled

それでは、新しいテストオプションのメソッドに移りましょう。

@DisplayName("Single test successful")
@Test
void testSingleSuccessTest() {
    log.info("Success");
}

@Test
@Disabled("Not implemented yet")
void testShowSomething() {
}

ご覧のとおり、新しい注釈を使用して、表示名を変更したり、コメント付きのメソッドを無効にしたりできます。

4.3. @AfterEachおよび@AfterAll

最後に、テスト実行後の操作に関連するメソッドについて説明します。

@AfterEach
void tearDown() {
    log.info("@AfterEach - executed after each test method.");
}

@AfterAll
static void done() {
    log.info("@AfterAll - executed after all test methods.");
}

@AfterAllのメソッドも静的メソッドである必要があることに注意してください。

5. アサーションと仮定

JUnit 5は、Java 8の新機能、特にラムダ式を最大限に活用しようとします。

5.1. アサーション

アサーションはorg.junit.jupiter.api.Assertions、に移動され、大幅に改善されました。 前述のように、アサーションでラムダを使用できるようになりました。

@Test
void lambdaExpressions() {
    List numbers = Arrays.asList(1, 2, 3);
    assertTrue(numbers.stream()
      .mapToInt(Integer::intValue)
      .sum() > 5, () -> "Sum should be greater than 5");
}

上記の例は簡単ですが、アサーションメッセージにラムダ式を使用する利点の1つは、遅延評価されることです。これにより、メッセージの構築に費用がかかる場合に時間とリソースを節約できます。

assertAll()、を使用してアサーションをグループ化することも可能になりました。これにより、グループ内で失敗したアサーションがMultipleFailuresErrorで報告されます。

 @Test
 void groupAssertions() {
     int[] numbers = {0, 1, 2, 3, 4};
     assertAll("numbers",
         () -> assertEquals(numbers[0], 1),
         () -> assertEquals(numbers[3], 3),
         () -> assertEquals(numbers[4], 1)
     );
 }

これは、障害の正確な場所を特定できるため、より複雑なアサーションを作成する方が安全であることを意味します。

5.2. 仮定

仮定は、特定の条件が満たされた場合にのみテストを実行するために使用されます。 これは通常、テストを適切に実行するために必要な外部条件に使用されますが、テスト対象に直接関係するものではありません。

assertTrue() assertFalse()、および assertingThat():を使用して仮定を宣言できます。

@Test
void trueAssumption() {
    assumeTrue(5 > 1);
    assertEquals(5 + 2, 7);
}

@Test
void falseAssumption() {
    assumeFalse(5 < 1);
    assertEquals(5 + 2, 7);
}

@Test
void assumptionThat() {
    String someString = "Just a string";
    assumingThat(
        someString.equals("Just a string"),
        () -> assertEquals(2 + 2, 4)
    );
}

仮定が失敗した場合、 TestAbortedException がスローされ、テストは単にスキップされます。

仮定はラムダ式も理解します。

6. 例外テスト

JUnit 5での例外テストには2つの方法があり、どちらも assertThrows()メソッドを使用して実装できます。

@Test
void shouldThrowException() {
    Throwable exception = assertThrows(UnsupportedOperationException.class, () -> {
      throw new UnsupportedOperationException("Not supported");
    });
    assertEquals("Not supported", exception.getMessage());
}

@Test
void assertThrowsException() {
    String str = null;
    assertThrows(IllegalArgumentException.class, () -> {
      Integer.valueOf(str);
    });
}

最初の例はスローされた例外の詳細を検証し、2番目の例は例外のタイプを検証します。

7. テストスイート

JUnit 5の新機能を継続するために、テストスイートに複数のテストクラスを集約して、それらを一緒に実行できるようにするという概念を探ります。 JUnit 5は、テストスイートを作成するために @SelectPackages@SelectClasses、の2つのアノテーションを提供します。

この初期段階では、ほとんどのIDEがこれらの機能をサポートしていないことに注意してください。

最初のものを見てみましょう:

@Suite
@SelectPackages("com.baeldung")
@ExcludePackages("com.baeldung.suites")
public class AllUnitTest {}

@SelectPackage は、テストスイートの実行時に選択されるパッケージの名前を指定するために使用されます。 この例では、すべてのテストを実行します。 2番目のアノテーション@SelectClassesは、テストスイートの実行時に選択されるクラスを指定するために使用されます。

@Suite
@SelectClasses({AssertionTest.class, AssumptionTest.class, ExceptionTest.class})
public class AllUnitTest {}

たとえば、上記のクラスは、3つのテストクラスを含むスイートを作成します。 クラスは単一のパッケージである必要はないことに注意してください。

8. 動的テスト

紹介したい最後のトピックは、実行時に生成されたテストケースを宣言して実行できるJUnit5の動的テスト機能です。 コンパイル時に固定数のテストケースを定義する静的テストとは異なり、動的テストでは、実行時にテストケースを動的に定義できます。

動的テストは、@TestFactory。でアノテーションが付けられたファクトリメソッドによって生成できます。コードを見てみましょう。

@TestFactory
Stream<DynamicTest> translateDynamicTestsFromStream() {
    return in.stream()
      .map(word ->
          DynamicTest.dynamicTest("Test translate " + word, () -> {
            int id = in.indexOf(word);
            assertEquals(out.get(id), translate(word));
          })
    );
}

この例は非常に単純で理解しやすいものです。 それぞれinoutという名前の2つのArrayListを使用して単語を翻訳します。 ファクトリメソッドは、 Stream Collection Iterable 、またはIteratorを返す必要があります。 私たちの場合、Java8を選択しましたストリーム。

@TestFactoryメソッドはプライベートまたは静的であってはならないことに注意してください。 テストの数は動的であり、ArrayListサイズによって異なります。

9. 結論

この記事では、JUnit5に伴う変更の概要を簡単に説明しました。

プラットフォームランチャー、IDE、その他の単体テストフレームワーク、ビルドツールとの統合などに関連して、JUnit5のアーキテクチャに大きな変更が加えられていることを確認しました。 さらに、JUnit5はJava8、特にLambdasとStreamの概念とより統合されています。

この記事で使用されている例は、GitHubプロジェクトにあります。