Introducción a los Tests Dinámicos

Los tests dinámicos en JUnit 5 permiten la creación de tests en tiempo de ejecución. A diferencia de los tests estáticos, que se definen de manera fija en el código, los tests dinámicos se generan y ejecutan de manera programática. Esto es útil cuando se necesita ejecutar una serie de tests que no se pueden definir de antemano, como pruebas basadas en datos externos o generados aleatoriamente.

Conceptos Clave

  • DynamicTest: Representa un test dinámico en JUnit 5.
  • DynamicContainer: Agrupa varios DynamicTest y otros DynamicContainer.
  • DynamicTest.stream(): Método para crear un flujo de tests dinámicos.

Creando Tests Dinámicos

Para crear tests dinámicos, se utiliza la anotación @TestFactory en un método que retorna una colección de DynamicTest o DynamicContainer.

Ejemplo Básico

import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.TestFactory;
import org.junit.jupiter.api.function.Executable;

import java.util.Arrays;
import java.util.Collection;

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

public class DynamicTestsExample {

    @TestFactory
    Collection<DynamicTest> dynamicTests() {
        return Arrays.asList(
            DynamicTest.dynamicTest("Test 1", () -> assertTrue(1 < 2)),
            DynamicTest.dynamicTest("Test 2", () -> assertTrue(2 < 3))
        );
    }
}

En este ejemplo, el método dynamicTests retorna una colección de DynamicTest. Cada DynamicTest se define con un nombre y un Executable que contiene el código del test.

Explicación del Código

  • @TestFactory: Indica que el método es una fábrica de tests dinámicos.
  • DynamicTest.dynamicTest: Método estático para crear un DynamicTest.
  • Executable: Interfaz funcional que representa el código del test.

Usando DynamicContainer

Los DynamicContainer permiten agrupar varios DynamicTest y otros DynamicContainer, lo que es útil para organizar tests complejos.

Ejemplo con DynamicContainer

import org.junit.jupiter.api.DynamicContainer;
import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.TestFactory;

import java.util.Arrays;
import java.util.Collection;

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

public class DynamicContainerExample {

    @TestFactory
    Collection<DynamicContainer> dynamicContainers() {
        return Arrays.asList(
            DynamicContainer.dynamicContainer("Container 1", Arrays.asList(
                DynamicTest.dynamicTest("Test 1.1", () -> assertTrue(1 < 2)),
                DynamicTest.dynamicTest("Test 1.2", () -> assertTrue(2 < 3))
            )),
            DynamicContainer.dynamicContainer("Container 2", Arrays.asList(
                DynamicTest.dynamicTest("Test 2.1", () -> assertTrue(3 < 4)),
                DynamicTest.dynamicTest("Test 2.2", () -> assertTrue(4 < 5))
            ))
        );
    }
}

Explicación del Código

  • DynamicContainer.dynamicContainer: Método estático para crear un DynamicContainer.
  • Arrays.asList: Utilizado para crear una lista de DynamicTest dentro de cada DynamicContainer.

Ejercicio Práctico

Ejercicio

Crea un test dinámico que verifique si una lista de números es par o impar. La lista de números debe ser generada aleatoriamente.

Solución

import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.TestFactory;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Random;

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

public class DynamicTestExercise {

    @TestFactory
    Collection<DynamicTest> dynamicTests() {
        List<Integer> numbers = generateRandomNumbers(10);
        List<DynamicTest> dynamicTests = new ArrayList<>();

        for (Integer number : numbers) {
            dynamicTests.add(DynamicTest.dynamicTest("Test if " + number + " is even or odd", () -> {
                if (number % 2 == 0) {
                    assertTrue(number % 2 == 0, number + " is even");
                } else {
                    assertTrue(number % 2 != 0, number + " is odd");
                }
            }));
        }

        return dynamicTests;
    }

    private List<Integer> generateRandomNumbers(int count) {
        List<Integer> numbers = new ArrayList<>();
        Random random = new Random();
        for (int i = 0; i < count; i++) {
            numbers.add(random.nextInt(100));
        }
        return numbers;
    }
}

Explicación del Código

  • generateRandomNumbers: Método auxiliar para generar una lista de números aleatorios.
  • dynamicTests.add: Añade un DynamicTest para cada número en la lista.
  • assertTrue: Verifica si el número es par o impar.

Conclusión

Los tests dinámicos en JUnit 5 proporcionan una manera flexible y poderosa de crear tests en tiempo de ejecución. Son especialmente útiles para escenarios donde los datos de prueba no se conocen de antemano o se generan dinámicamente. Con DynamicTest y DynamicContainer, puedes organizar y ejecutar tests de manera eficiente y estructurada.

En el siguiente módulo, exploraremos las mejores prácticas y consejos para escribir tests efectivos y organizar el código de tests.

© Copyright 2024. Todos los derechos reservados