JUnit 5の@TestInstanceアノテーション

  • link:/category/testing/ [テスト]

  • JUnit

1. 前書き

多くの場合、テストクラスには、テスト中のシステム、モック、またはテストで使用されるデータリソースを参照するメンバー変数が含まれます。 *デフォルトでは、JUnit 4と5は両方とも、各テストメソッドを実行する前にテストクラスの新しいインスタンスを作成します。*これにより、テスト間で状態を明確に分離できます。
このチュートリアルでは、https://www.baeldung.com/junit-5 [JUnit 5]が_ @ TestInstance_アノテーションを使用してテストクラスのライフサイクルを変更する方法を学習します。 また、大規模なリソースの管理やテスト間のより複雑な関係の管理にこれがどのように役立つかについても説明します。

2. デフォルトのテストライフサイクル

まず、JUnit 4および5に共通のデフォルトのテストクラスのライフサイクルを見てみましょう。
class AdditionTest {

    private int sum = 1;

    @Test
    void addingTwoReturnsThree() {
        sum += 2;
        assertEquals(3, sum);
    }

    @Test
    void addingThreeReturnsFour() {
        sum += 3;
        assertEquals(4, sum);
    }
}
このコードは、JUnit 5が必要としない_public_キーワードがないことを除けば、JUnit 4または5のテストコードである可能性があります。
各テストメソッドが呼び出される前に_AdditionTest_の新しいインスタンスが作成されるため、これらのテストは合格です。 つまり、変数_sum_の値は、各テストの実行前に常に_1_に設定されます。
テストオブジェクトの共有インスタンスが1つしかない場合、変数_sum_は各テスト後にその状態を保持します。 その結果、2番目のテストは失敗します。

3. @BeforeClass_および @ BeforeAll_アノテーション

オブジェクトが複数のテストにわたって存在する必要がある場合があります。 テストデータとして使用する大きなファイルを読みたいと想像してみましょう。 すべてのテストの前にそれを繰り返すのは時間がかかるかもしれないので、一度読んでテストフィクスチャ全体でそれを保持することを好むかもしれません。
JUnit 4は_ @ BeforeClass_アノテーションでこれに対処します。
private static String largeContent;

@BeforeClass
public static void setUpFixture() {
    // read the file and store in 'largeContent'
}
  • JUnit 4の_ @ BeforeClass_ staticで注釈付けされた変数とメソッドを作成する必要があることに注意してください。

    JUnit 5は異なるアプローチを提供します。 クラスの静的メンバーを操作するために、静的関数で使用される_ @ BeforeAll_注釈を提供します。
    ただし、テストインスタンスのライフサイクルが_per-class_に変更されている場合は、_ @ BeforeAll_をインスタンス関数およびインスタンスメンバーと共に使用することもできます。

4. _ @ TestInstance_アノテーション

_ @ TestInstance_アノテーションを使用すると、JUnit 5テストのライフサイクルを設定できます。
  • _ @ TestInstance_には2つのモードがあります。* 1つは_LifeCycle.PER_METHOD_(デフォルト)です。 もう1つは_ LifeCycle.PER_CLASS _です。 後者により、JUnitにテストクラスのインスタンスを1つだけ作成し、テスト間で再利用するように依頼できます。

    テストクラスに_ @ TestInstance_アノテーションを付けて、_LifeCycle.PER_CLASS_モードを使用してみましょう。
@TestInstance(LifeCycle.PER_CLASS)
class TweetSerializerUnitTest {

    private String largeContent;

    @BeforeAll
    void setUpFixture() {
        // read the file
    }

}
ご覧のとおり、変数や関数はいずれも静的ではありません。 _PER_CLASS_ *ライフサイクルを使用する場合、_ @ BeforeAll_に* instanceメソッドを使用できます。
また、1つのテストによってインスタンス変数の状態に加えられた変更が、他のテストから見えるようになることにも注意する必要があります。

5. _ @ TestInstance(PER_CLASS)_の使用

5.1. 高価なリソース

この注釈は、すべてのテストが非常に高価になる前にクラスをインスタンス化するときに役立ちます。 例としては、データベース接続の確立、または大きなファイルのロードがあります。
これを解決すると、以前は静的変数とインスタンス変数が複雑に混ざり合っていましたが、共有テストクラスインスタンスでよりクリーンになりました。

5.2. 故意に状態を共有する

*状態の共有は通常、単体テストではアンチパターンですが、統合テストでは役立ちます。*クラスごとのライフサイクルは、状態を意図的に共有する順次テストをサポートします。 これは、特にテスト対象のシステムを適切な状態にするのが遅い場合に、後のテストが前のテストからの手順を繰り返すことを避けるために必要な場合があります。
状態を共有する場合、JUnit 5はすべてのテストを順番に実行するために、タイプレベルの_https://www.baeldung.com/junit-5-test-order [@TestMethodOrder] _アノテーションを提供します。 次に、テストメソッドで_https://www.baeldung.com/junit-5-test-order [@Order] _アノテーションを使用して、選択した順序で実行できます。
@TestMethodOrder(OrderAnnotation.class)
class OrderUnitTest {

    @Test
    @Order(1)
    void firstTest() {
        // ...
    }

    @Test
    @Order(2)
    void secondTest() {
        // ...
    }

}

5.3. 状態を共有する

テストクラスの同じインスタンスを共有する際の課題は、一部のメンバーをテスト間でクリーンアップする必要があり、一部のメンバーはテスト全体の間維持する必要があることです。
  • https://www.baeldung.com/junit-before-beforeclass-beforeeach-beforeall [@BeforeEach] _または @ AfterEach_。アノテーションが付けられたメソッドを使用して、テスト間でクリーニングする必要がある変数をリセットできます。

6. 結論

このチュートリアルでは、_ @ TestInstance_アノテーションと、それを使用してJUnit 5テストのライフサイクルを構成する方法について学習しました。
また、共有リソースの処理や順次テストの意図的な作成の観点から、テストクラスの単一のインスタンスを共有することが有用である理由についても検討しました。
いつものように、このチュートリアルのコードはhttps://github.com/eugenp/tutorials/tree/master/testing-modules/junit-5-advanced[GitHubで発見]です。