JUnit でパラメータ付きテストを繰り返す方法

以前の記事では、テストの実行を繰り返す方法や、テストをパラメータ化する方法について見てきました。
今回は、これらのアイデアを組み合わせて、パラメータ付きのテストを繰り返す方法について見ていきましょう。

以前の記事で「テストの実行を繰り返す」という例を元にしますが、これはN桁の乱数を生成するメソッドです。

最初は、他の記事で述べたアノテーションを組み合わせるだけで十分だと考えがちですね。@RepeatedTest@ParameterizedTestを組み合わせるわけですが、残念ながらJUnitでは現在、この機能はサポートされていません。幸いなことに代替案は非常にシンプルです。

パラメータ付きテストから始めるとしましょう:

/**
 * パラメータ:
 * 1. int - 最小値。
 * 2. int - 最大値。
 * 3. int - 生成された乱数の桁数。
 */
private static Stream<Arguments> randomNumberGeneratorParams() {
    return Stream.of(
        Arguments.of(1, 9, 1),
        Arguments.of(10, 99, 2),
        Arguments.of(100, 999, 3),
        Arguments.of(1000, 9999, 4),
        Arguments.of(10000, 99999, 5)
    );
}

@ParameterizedTest
@MethodSource(value = "randomNumberGeneratorParams")
@DisplayName(value = "ランダムな数値のジェネレータ")
void random_numbers_generator(int low, int high, int numOfDigits) {    
    var actual = RandomUtil.generateNumber(numOfDigits);
    assertTrue(high >= actual, "エラー、乱数が大きすぎます");
    assertTrue(low <= actual, "エラー、実際の値が小さすぎます");
}

// テスト合格: 5件中 5件 ✅
// [1] 最小値 = 1, 最大値 = 9, 桁数 = 1 -> 生成された数字 6
// [2] 最小値 = 10, 最大値 = 99, 桁数 = 2 -> 生成された数字 56
// [3] 最小値 = 100, 最大値 = 999, 桁数 = 3 -> ...
// [4] 最小値 = 1000, 最大値 = 9999, 桁数 = 4
// [5] 最小値 = 10000, 最大値 = 99999, 桁数 = 5

これだけのテストは信頼性があまりないかもしれませんね。理由は、各ユースケース(1桁、2桁、3桁、4桁、5桁の数値を生成する)について乱数を1つしか生成していないからです。

乱数関数が正しいことを確実に確認するには、各範囲またはユースケースでN個の番号を生成し、それらがすべてテストを満たすことを確認する方がよいでしょう。

やり方を見てみましょう:

private static final int NUMBER_REPETITIONS = 1_000;

/**
 * パラメータ:
 * 1. int - 最小値。
 * 2. int - 最大値。
 * 3. int - 生成された乱数の桁数。
 */
private static Stream<Arguments> randomNumberGeneratorParams() {
    return Stream.of(
        Arguments.of(1, 9, 1),
        Arguments.of(10, 99, 2),
        Arguments.of(100, 999, 3),
        Arguments.of(1000, 9999, 4),
        Arguments.of(10000, 99999, 5)
    );
}

@ParameterizedTest
@MethodSource(value = "randomNumberGeneratorParams")
@DisplayName(value = "ランダムな数値のジェネレータ")
void random_numbers_generator(int low, int high, int numOfDigits) {
 int iterationCount = 1;
 do {   // <- do-whileループを使って乱数の生成を繰り返します
     var actual = RandomUtil.generateNumber(numOfDigits);
     assertTrue(high >= actual, "エラー、乱数が大きすぎます");
     assertTrue(low <= actual, "エラー、実際の値が小さすぎます");
     iterationCount++;
 } while (iterationCount <= NUMBER_REPETITIONS);
}

// テスト合格: 5件中 5件 ✅
// [1] 最小値 = 1, 最大値 = 9, 桁数 = 1 -> 生成された数値: 6, 3, 1, 3, 4, 2, 6, 8, 9...総数 1_000_000個
// [2] 最小値 = 10, 最大値 = 99, 桁数 = 2 -> ...
// [3] 最小値 = 100, 最大値 = 999, 桁数 = 3
// [4] 最小値 = 1000, 最大値 = 9999, 桁数 = 4
// [5] 最小値 = 10000, 最大値 = 99999, 桁数 = 5

この方法で、NUMBER_REPETITIONSに指定された回数だけ多くの数を生成し、そのすべてがテストのアサーションを満たすことを確認できます。

こちらの記事はdev.toの良い記事を日本人向けに翻訳しています。
https://dev.to/gekyzo/junit-como-repetir-un-test-con-parametros-1l15