JUnit @Parameters を使用した例によるパラメーター化されたテスト

⚡ スマートサマリー

パラメータ化されたテスト JUnit 異なる入力値を用いて同じテストメソッドを繰り返し実行することで、1つのメソッドで多くのシナリオを網羅できます。@RunWithおよび@Parametersアノテーションは、各イテレーションで使用するデータセットを提供します。

  • 🔘 データソース: 静的メソッド @Parameters は配列のコレクションを返し、各配列が 1 つのテスト反復になります。
  • ☑️ ランナー: @RunWith(Parameterized.class) はデフォルトのブロックを置き換えますJUnit4ClassRunnerは、データ行ごとにクラスを一度再構築します。
  • コンストラクタ: 1つのパブリックコンストラクタは、テストメソッドが検証するインスタンスフィールドに、1行のデータを格納します。
  • 🧪 実例: 5 つの入力行が sum() テストを駆動し、 JUnit レポートを表示 5回中5回実行され、失敗はゼロです。
  • 🛠️ JUnit 5: @ParameterizedTest に @ValueSource、@CsvSource、または @MethodSource を組み合わせると、ランナーとコンストラクターの両方が削除されます。
  • 📌 落とし穴: 非静的な @Parameters メソッド、2 つのパブリック コンストラクタ、または junit-jupiter-params の依存関係の欠落により、実行が停止します。

JUnit @RunWithおよび@Parametersアノテーションを使用したパラメータ化テスト

パラメータ化テストとは何ですか JUnit?

A パラメータ化されたテスト これは、異なる値を使用して同じテストメソッドを繰り返し実行するテストです。入力値と期待される結果のみが異なるテストを作成する際に、開発者が時間を節約するのに役立ちます。

パラメータ化されたテストを使用すると、データソースからデータを取得するテストメソッドを設定できます。これにより、最も単純な形式になります。 データ駆動型テスト 内部で利用可能 JUnit それ自体で動作し、外部ライブラリは不要です。

異なる数値を合計する簡単なテストを考えてみましょう。コードは次のようになります。

JUnit sum メソッドに対して assertEquals を 3 回繰り返すテストメソッド

上記のアプローチでは、多くの冗長性が生じます。新しい数値のペアごとに、同じメソッド内に別のアサート文が必要となり、最初のアサートが失敗すると、それに続くすべてのアサートが隠蔽されてしまいます。

もっとシンプルな方法が必要です。パラメータ化されたテストを使用すれば、10個のデータ入力を提供するメソッドを1つ追加するだけで、テストが自動的に10回実行されます。

パラメータ化されたオブジェクトを作成する手順 JUnit ホイール試乗

以下のコードは、パラメータ化テストの例を示しています。このコードは、サンプルプロジェクト全体で使用されているスペルであるAirthematicクラスのsum()メソッドをテストします。

ステップ1) クラスを作成します。この例では、sum(int, int) メソッドを使用して 2 つの数値を入力し、入力された数値の合計を返します。

Airthematicクラスは、2つのint引数を加算するpublic sumメソッドを宣言しています。

ステップ2) パラメータ化されたテストクラスを作成します。

@RunWith(Parameterized.class) アノテーションと 4 つのプライベート フィールドを持つテスト クラス ヘッダー

Code 説明

  • Code ライン11: @RunWith(Parameterized.class) を使用してテストクラスにアノテーションを付けます。
  • Code ライン13: 変数「firstNumber」をプライベートとして宣言し、型を int として宣言します。
  • Code ライン14: 変数「secondNumber」をプライベート変数として宣言し、型をintとします。
  • Code ライン15: 変数「expectedResult」をプライベートとして宣言し、型をintとします。
  • Code ライン16: 変数「airthematic」をプライベート変数として宣言し、型をAirthematicとします。

@RunWith(class_name.class): @RunWith アノテーションは、ランナークラス名を指定するために使用されます。パラメーターとして型を指定しない場合、ランタイムは自動的に選択します。 ブロックJUnit4クラスランナー デフォルトでは

このクラスは、新しいテストインスタンスで実行されるテストを担当します。 JUnit セットアップ (リソースの関連付け) やティアダウン (リソースの解放) などのライフサイクル メソッドについては、 JUnit テストフィクスチャ チュートリアル。

パラメータ化するには、クラスに@RunWithアノテーションを付け、テストに必要な.classを渡す必要があります。

ステップ3) テストデータを格納するコンストラクタを作成します。このコンストラクタは3つの変数を格納します。

3 つの int 引数をインスタンスフィールドに割り当てるパラメータ付きテストコンストラクタ

ステップ4) テスト データを生成して返す静的メソッドを作成します。

@Parameterized.Parameters アノテーションが付与された静的入力メソッドで、2 次元の Object 配列を返します。

Code ライン32,33: 2次元配列を作成します(加算のための入力パラメータを提供します)。入力メソッドの戻り値の型がコレクションであるため、asListメソッドを使用してデータをリスト型に変換します。

Code ライン30: 使い方 @パラメーター アノテーションを使用して、テストを実行するための入力データのセットを作成します。

@Parameters アノテーションで識別される静的メソッドは、Collection を返します。Collection の各エントリは、テストの 1 つのイテレーションの入力データになります。要素 {1,2,3} を考えてみましょう。ここで、

  • firstNumber = 1
  • secondNumber = 2
  • 期待される結果 = 3

ここでは、クラスが複数回インスタンス化される際に、各配列要素がコンストラクタに1つずつ渡されます。したがって、この例で宣言された5つの配列は、以下の5回の実行結果を生成します。

繰り返し 最初の数字 2番目の番号 期待される結果 コンソールライン
【0] 1 2 3 の合計 Numbers = : 3
【1] 11 22 33 の合計 Numbers = : 33
【2] 111 222 333 の合計 Numbers = : 333
【3] 10 9 19 の合計 Numbers = : 19
【4] 100 9 109 の合計 Numbers = : 109

ステップ5) 完全なコード。

インポート、コンストラクタ、@Parameters メソッド、@Test メソッドを含む完全な AirthematicTest リスト

Code 説明:

  • Code ライン25: @Before アノテーションを使用してリソース (ここでは Airthematic.class) を設定します。@Before アノテーションは、各テストケースの前に実行されるために使用されます。このアノテーションには、テストの前提条件が含まれています。
  • Code ライン36: @Test アノテーションを使用してテストを作成します。
  • Code ライン39: アンケートの作成 assert文 合計値が予想値と一致するかどうかを確認する。

ステップ6) パラメータ化されたテストを実行するためのテストランナークラスを作成します。

TestRunner クラスは AirthematicTest.class を渡します JUnitCore.runClassesと印刷エラー

Code 説明:

  • Code ライン8: テストクラスで実行されるメインメソッドを宣言します JUnit テスト。
  • Code ライン9: テストケースの実行 JUnitCore.runClasses は、テストクラス名をパラメータとして受け取ります (この例では AirthematicTest.class を使用しています)。
  • Code ライン11: forループを使用して結果を処理し、失敗した結果を出力する。
  • Code ライン13: 成功した結果を出力します。

出力:

以下が出力結果です。テストは失敗なく成功しました。 trace、以下に示すとおりです。 JUnit ビューでは、単一のテストではなく、データ行ごとに1つのエントリが表示されます。

Eclipse JUnit レポートを表示 パラメータ化されたクラスで5/5実行、エラー0、失敗0

コンソールに表示される結果をご覧ください。そこには2つの数値の加算結果が表示されます。

Eclipse コンソールに1つの合計を印刷します Numbers 5つのパラメータ行それぞれに対応する行

パラメータ化されたテスト JUnit 5(@ParameterizedTest付き)

上記の例は、 JUnit 4. JUnit 5 (Jupiter) ではランナー モデルが完全に削除されるため、@RunWith(Parameterized.class)、データ コンストラクタ、インスタンス フィールドはすべて消えます。 JUnit 上記のコード4は廃止されていません。 JUnit プラットフォームは従来のエンジンを介して動作します。ただし、新しいテストは通常​​、@ParameterizedTest を使用して記述されます。

テスト注釈には junit-jupiter-api が必要で、 junit-jupiter-params パラメータ化されたサポートのため。2つ目のアーティファクトがないと、ソースアノテーションは全く解決されません。

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;

class AirthematicTest {

    // one row per iteration, no constructor and no runner
    @ParameterizedTest(name = "{0} + {1} = {2}")
    @CsvSource({"1, 2, 3", "11, 22, 33", "111, 222, 333", "10, 9, 19", "100, 9, 109"})
    void sumOfTwoNumbers(int firstNumber, int secondNumber, int expectedResult) {
        assertEquals(expectedResult, new Airthematic().sum(firstNumber, secondNumber));
    }
}

Jupiterは複数の引数ソースを提供しており、適切なソースはデータの形状によって異なります。

ソース注釈 用品 次のようなときに使用します
@ValueSource リテラルの単一列 このテストは引数を1つだけ取ります。
@CsvSource インラインのカンマ区切り行 ファイル内で読み取れる数値と文字列の小さなテーブル
@CsvFileSource テストクラスパス上のCSVファイルから読み取られた行数 データセットが大きいか、コード外で管理されている
@MethodSource 引数のストリームを返す静的ファクトリ 実物、計算値、またはランダム化データが必要です
@EnumSource 列挙型の定数 すべての列挙値は実行されなければならない

初心者が陥りがちなルールが2つあります。1つ目は、通常の@Testメソッドに付けられたソースアノテーションは黙って無視されるため、メソッドには@ParameterizedTestを付ける必要があるということです。2つ目は、@CsvSource内の引用符で囲まれていない空の値はnullとして読み取られ、引用符で囲まれた空の値は空の文字列として読み取られるということです。

その JUnit この記事で使用されている 4 つの注釈は、Jupiter では次のようにマッピングされます。@RunWith(Parameterized.class) は @ParameterizedTest とソース注釈に、@Parameters は @MethodSource または @CsvSource に、@Before は @BeforeEach になります。完全なリストについては、 JUnit アノテーション チュートリアル。

パラメータ化テストの利点と限界

パラメータ化にはデメリットもあります。重複を排除できる反面、テストの記述方法にも制約が生じるため、既存のテストスイートを変換する前に、その両面を理解しておくことが重要です。

優位性

  • Less 複製: この記事の最初のスクリーンショットに示すように、ある方法では、ほぼ同じ内容のassert文のブロックを置き換えます。
  • より安価な保険: エッジケースを追加すると、新しいデータ行全体ではなく、データ行が1つ増えるだけです。 テストケース 方法。
  • 正確な報告: 各反復は個別に報告されるため、 JUnit このビューでは、単一の集計されたエラーではなく、どの行がエラーになったかを正確に特定できます。
  • 集中型データ: 入力は単一のメソッド内に存在し、アサーションを変更することなく、後でCSVファイルやファクトリに移動できます。

製品制限

  • 主張の1つの形態: どの行でも同じアサーションが実行されるため、異なるチェックが必要なシナリオには、独自のテストメソッドが必要になります。
  • クラスレベルのスコープ JUnit 4: ランナーはクラス全体をパラメータ化するため、そのクラス内の無関係な @Test メソッドも行ごとに 1 回実行されます。
  • 判読不能なレポート: 名前テンプレートがない場合、失敗は testAirthematicTest[3] と表示されますが、これは壊れたデータについては何も示していません。
  • 大容量のインラインデータ: 大きな配列はテストロジックを圧迫するため、代わりに@CsvFileSourceまたは@MethodSourceファクトリに移動してください。

よくある間違い JUnit パラメータ化テスト

パラメータ化されたエラーのほとんどは、単一のアサーションが実行される前に発生する初期化エラーです。以下の表は、最も頻繁に発生するメッセージとその発生原因を示しています。

メッセージ 原因となる 修正する
テストクラスにはパブリックコンストラクタが1つだけ必要です。 クラスはパブリックコンストラクタを宣言しないか、あるいは2つ宣言する。 データ列と一致するパラメータを持つパブリックコンストラクタを1つ保持する
クラスにパブリックな静的パラメータメソッドはありません @Parameters メソッドは public static ではないか、または間違った型を返します public static Collection として宣言し、Arrays.asList(…) を返します。
IllegalArgumentException: 引数の数が間違っています 行の幅がコンストラクタパラメータリストよりも広いか狭いか コレクション内のすべての配列の幅をコンストラクタと同じにする
設定エラー: 引数プロバイダーがありません Jupiterテストは、ソース注釈のない@ParameterizedTestを使用します。 @ValueSource、@CsvSource、@CsvFileSource、@MethodSource、または@EnumSourceを追加します。
ソース注釈は何も機能していないようです メソッドには、@ParameterizedTest ではなく @Test という注釈が付けられています。 @Test を @ParameterizedTest に置き換え、junit-jupiter-params をインポートします。

もう一つの落とし穴は共有状態です。なぜなら JUnit 行ごとに新しいインスタンスが構築され、静的フィールドに保持されているものはすべてのイテレーションで保持され、行 [0] によって書き込まれた値は行 [4] の結果を静かに変更する可能性があります。行ごとの状態はインスタンスフィールドに保持し、共有リソースは @Before または @BeforeEach メソッドでリセットします。テストの分離に関する一般的なガイダンスについては、 単体テスト チュートリアル。

よくあるご質問

TestNG 各テストメソッドごとに参照される@DataProviderメソッドを通じて行を提供するので、クラス内の無関係なテストには影響しません。 JUnit 4はランナーを通してクラス全体をパラメータ化する。 JUnit 5 では、メソッドごとの @ParameterizedTest でそのギャップが解消されます。

Yes. JUnit 4 は @Parameters(name = “{index}: sum({0},{1})={2}”) を受け入れ、Jupiter は @ParameterizedTest(name = “…”) を受け入れます。プレースホルダーは実行時に置き換えられるため、エラー レポートには、単なるインデックスを表示する代わりに、問題のある行の名前が表示されます。

Yes. JUnit 4 では、パブリックな非静的フィールドに対して @Parameter(0) と @Parameter(1) がサポートされ、クラスはデフォルトコンストラクタに依存します。フィールドインジェクションとデータコンストラクタを組み合わせると、パブリックコンストラクタが 1 つしかないというエラーが発生します。

JUnit 4 では junit アーティファクトのみが必要です。なぜなら、パラメーター化されたランナーはその中に含まれて同梱されているからです。 JUnit 5 では junit-jupiter-api に加えて junit-jupiter-params が必要です。このアーティファクトがないと、@ParameterizedTest およびすべてのソース アノテーションが解決されません。

Jupiter は、テスト クラスパスから行を読み込む @CsvFileSource(resources = “/data.csv”, numLinesToSkip = 1) を提供します。 JUnit 4 には組み込みの同等の機能がないため、@Parameters メソッドはコレクションを返す前にファイルを開いて解析する必要があります。

In JUnit 4. 可能ですが、ランナーはクラス全体をパラメータ化するため、各メソッドはデータ行ごとに一度実行されます。Jupiter は個々のメソッドをパラメータ化するため、同じクラスの通常の @Test メソッドは依然として正確に 1 回実行されます。

AIアシスタントはメソッドシグネチャを読み取り、手書きの表では見落とされがちな、ゼロ、負の値、最大値、オーバーフロー入力などの境界行を提案します。 Rev生成された期待される結果はすべて確認してください。モデルは、もっともらしい行に誤った答えを導き出す可能性があるからです。

GitHubコパイロット 足場を素早く製造するが、しばしば混合する JUnit 4 と Jupiter はインポートを行い、場合によってはプレーンな @Test メソッドにソース注釈を残します。スイートを実行する前にインポートを確認してください。