JUnit @Parameters を使用した例によるパラメーター化されたテスト
⚡ スマートサマリー
パラメータ化されたテスト JUnit 異なる入力値を用いて同じテストメソッドを繰り返し実行することで、1つのメソッドで多くのシナリオを網羅できます。@RunWithおよび@Parametersアノテーションは、各イテレーションで使用するデータセットを提供します。
パラメータ化テストとは何ですか JUnit?
A パラメータ化されたテスト これは、異なる値を使用して同じテストメソッドを繰り返し実行するテストです。入力値と期待される結果のみが異なるテストを作成する際に、開発者が時間を節約するのに役立ちます。
パラメータ化されたテストを使用すると、データソースからデータを取得するテストメソッドを設定できます。これにより、最も単純な形式になります。 データ駆動型テスト 内部で利用可能 JUnit それ自体で動作し、外部ライブラリは不要です。
異なる数値を合計する簡単なテストを考えてみましょう。コードは次のようになります。
上記のアプローチでは、多くの冗長性が生じます。新しい数値のペアごとに、同じメソッド内に別のアサート文が必要となり、最初のアサートが失敗すると、それに続くすべてのアサートが隠蔽されてしまいます。
もっとシンプルな方法が必要です。パラメータ化されたテストを使用すれば、10個のデータ入力を提供するメソッドを1つ追加するだけで、テストが自動的に10回実行されます。
パラメータ化されたオブジェクトを作成する手順 JUnit ホイール試乗
以下のコードは、パラメータ化テストの例を示しています。このコードは、サンプルプロジェクト全体で使用されているスペルであるAirthematicクラスのsum()メソッドをテストします。
ステップ1) クラスを作成します。この例では、sum(int, int) メソッドを使用して 2 つの数値を入力し、入力された数値の合計を返します。
ステップ2) パラメータ化されたテストクラスを作成します。
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つの変数を格納します。
ステップ4) テスト データを生成して返す静的メソッドを作成します。
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) 完全なコード。
Code 説明:
- Code ライン25: @Before アノテーションを使用してリソース (ここでは Airthematic.class) を設定します。@Before アノテーションは、各テストケースの前に実行されるために使用されます。このアノテーションには、テストの前提条件が含まれています。
- Code ライン36: @Test アノテーションを使用してテストを作成します。
- Code ライン39: アンケートの作成 assert文 合計値が予想値と一致するかどうかを確認する。
ステップ6) パラメータ化されたテストを実行するためのテストランナークラスを作成します。
Code 説明:
- Code ライン8: テストクラスで実行されるメインメソッドを宣言します JUnit テスト。
- Code ライン9: テストケースの実行 JUnitCore.runClasses は、テストクラス名をパラメータとして受け取ります (この例では AirthematicTest.class を使用しています)。
- Code ライン11: forループを使用して結果を処理し、失敗した結果を出力する。
- Code ライン13: 成功した結果を出力します。
出力:
以下が出力結果です。テストは失敗なく成功しました。 trace、以下に示すとおりです。 JUnit ビューでは、単一のテストではなく、データ行ごとに1つのエントリが表示されます。
コンソールに表示される結果をご覧ください。そこには2つの数値の加算結果が表示されます。
パラメータ化されたテスト 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 メソッドでリセットします。テストの分離に関する一般的なガイダンスについては、 単体テスト チュートリアル。









