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 cadaDynamicContainer
.
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.
Curso de JUnit
Módulo 1: Introducción a JUnit
Módulo 2: Anotaciones Básicas de JUnit
- Entendiendo @Test
- Usando @Before y @After
- Usando @BeforeClass y @AfterClass
- Ignorando Tests con @Ignore
Módulo 3: Aserciones en JUnit
Módulo 4: Tests Parametrizados
- Introducción a los Tests Parametrizados
- Creando Tests Parametrizados
- Usando @ParameterizedTest
- Tests Parametrizados Personalizados
Módulo 5: Suites de Tests
Módulo 6: Mocking con JUnit
Módulo 7: Características Avanzadas de JUnit
Módulo 8: Mejores Prácticas y Consejos
- Escribiendo Tests Efectivos
- Organizando el Código de Tests
- Desarrollo Guiado por Tests (TDD)
- Integración Continua con JUnit