JUnit Cómo repetir un test con parámetros
Tags: testing, spanish, spring, java
Published: 2022-11-16 23:00:00

En publicaciones anteriores hemos visto de qué maneras se podía [repetir la ejecución de un test](https://dev.to/gekyzo/como-repetir-un-test-n-iteraciones-36pd?preview=8d5432e73aff87d94e34f32a0e291f6b934a91366ba4c244147aa297e347bf61455da58a71aba758bc0292a658d687a412063be791dfa6a4a76a5df8), así como la manera de [parametrizar un test](https://dev.to/gekyzo/junit-como-ejecutar-un-test-con-parametros-4cp3?preview=a4e5383b084aa4788dc11b0a971147c820f6e17c8a8dff5aafffdad71e0854457949698c8f50fe1c35748a5967db228910b1b0ac698de492219a6418).
En esta ocasión vamos a ver **cómo unir ambas ideas para repetir un test parametrizado**.

Utilizaremos para ello el mismo ejemplo de la publicación repetir la ejecución de un test, recuerdo que se trata de un **método que genera un número aleatorio de N dígitos**.

Inicialmente, puede que pensamos que es suficiente con combinar las anotaciones mencionadas en las otras publicaciones, `@RepeatedTest` + `@ParameterizedTest`, pero lamentablemente **JUnit no soporta esta funcionalidad** actualmente. Por fortuna la **solución alternativa** es muy simple.

Supongamos que partimos de un test parametrizado:


```java
/**
 * Parameters:
 * 1. int - The lower bound.
 * 2. int - The upper bound.
 * 3. int - The number of digits of the random generated value.
 */
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 = "Random numbers generator")
void random_numbers_generator(int low, int high, int numOfDigits) {    
    var actual = RandomUtil.generateNumber(numOfDigits);
    assertTrue(high >= actual, "Error, random is too high");
    assertTrue(low <= actual, "Error, actual is too low");
}

// Test passed: 5 of 5 ✅
// [1] low = 1, high = 9, numOfDigits = 1 -> numero generado 6
// [2] low = 10, high = 99, numOfDigits = 2 -> número generado 56
// [3] low = 100, high = 999, numOfDigits = 3 -> ...
// [4] low = 1000, high = 9999, numOfDigits = 4
// [5] low = 10000, high = 99999, numOfDigits = 5
```

Podemos imaginar que **este test no es muy fiable**, ya que sólo hemos generado 1 número aleatorio para cada uno de nuestros casos de uso (generar un número de 1, 2, 3, 4 y 5 dígitos).

Para confirmar con seguridad que la función aleatoria es correcta, sería mejor si pudiéramos **generar N números en cada rango** o caso de uso, y comprobar que todos ellos cumplen con el test.

Veamos cómo hacerlo:

```java
private static final int NUMBER_REPETITIONS = 1_000;

/**
 * Parameters:
 * 1. int - The lower bound.
 * 2. int - The upper bound.
 * 3. int - The number of digits of the random generated value.
 */
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 = "Random numbers generator")
void random_numbers_generator(int low, int high, int numOfDigits) {
 int iterationCount = 1;
 do {	// <- Mediante el uso del loop do-while, podemos iterar la generación de los números aleatorios
     var actual = RandomUtil.generateNumber(numOfDigits);
     assertTrue(high >= actual, "Error, random is too high");
     assertTrue(low <= actual, "Error, actual is too low");
     iterationCount++;
 } while (iterationCount <= NUMBER_REPETITIONS);
}

// Test passed: 5 of 5 ✅
// [1] low = 1, high = 9, numOfDigits = 1 -> números generados: 6, 3, 1, 3, 4, 2, 6, 8, 9...1_000_000 de números generados
// [2] low = 10, high = 99, numOfDigits = 2 -> ...
// [3] low = 100, high = 999, numOfDigits = 3
// [4] low = 1000, high = 9999, numOfDigits = 4
// [5] low = 10000, high = 99999, numOfDigits = 5
```

De esta manera, el test **generará tantos números como indiquemos** en `NUMBER_REPETITIONS`, y **confirmará que todos ellos cumplen** con las afirmaciones del test.