JUNIT 5
Test de prueba
CONTENIDO
1. Dependencias Maven necesarias para JUnit 5
2. Test unitarios con JUnit 5
3. Test para probar excepciones
4. Test con restricciones de tiempo. Timeout
5. Test parametrizado
a. Usando tipos primitivos: Con @ValueSource, @CSVSource, @CSVFilesource
b. Usando objetos: Con @MethodSource
6. APIExtension
7. Suites y filtros
8. Ordenar tests
9. AssertJ
10.Ciclo de vida
1. Dependencias Maven necesarias para JUnit 5
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
Fichero: <artifactId>junit-jupiter</artifactId>
<version>5.9.2</version>
pom.xml <scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.9.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-suite-engine</artifactId>
<version>1.8.1</version>
</dependency>
</dependencies>
2. Test unitarios con JUnit 5. Ejemplos
Ejemplo simple
@Test
@DisplayName("esPrimoNumeroPrimoIgualADos")
void esPrimoNumeroPrimoIgualADos() {
int num = 2;
boolean expected = true;
boolean result = Ejercicios.esPrimo(num);
assertEquals(expected, result);
}
2. Test unitarios con JUnit 5. Ejemplos
Ejemplo simple usando una aserción más apropiada
@Test
@DisplayName("esPrimoNumeroPrimoIgualADos")
void esPrimoNumeroPrimoIgualADos() {
int num = 2;
boolean result = Ejercicios.esPrimo(num);
assertTrue(result);
}
2. Test unitarios con JUnit 5. Ejemplos
Ejemplo cuando tenemos que comprobar un valor double
@Test
void divisionTestConCocientePeriodico(){
double operador1 = 10;
double operador2 = 3;
double expected = 3.33;
double result = Calculadora(operador1, operador2);
assertEquals(expected, result, 0.01);
Delta o margen
} de error
2. Test unitarios con JUnit 5. Ejemplos
Hacer que un test falle para indicar que no está implementado
@Test
@DisplayName("Este Test falla")
public void esteTestFalla(){
Assertions.fail("Not implemented yet");
}
2. Test unitarios con JUnit 5. Ejemplos
Deshabilitar un test temporalmente y así evitar comentarlo
@Test
@DisplayName("EsPrimo Skipped Test")
@Disabled("Este tests no se ejecuta")
void esPrimoSkippedTest() {
// not executed
int num = 2;
boolean result = Ejercicios.esPrimo(num);
assertTrue(result);
}
3. Test para probar excepciones
Comprobamos que se lanza una excepción determinada
@Test
@DisplayName("Divide by Zero throws ArithmeticException")
void exceptionTesting() {
Exception exception = assertThrows(ArithmeticException.class,
() -> calculator.divide(1, 0));
assertEquals("/ by zero", exception.getMessage());
}
Función Lambda
3. Test para probar excepciones
Test para comprobar una excepción, mejor diseñada
@Test
@DisplayName("Divide by Zero throws IllegalArgument Exception")
void divideByZeroThrowsIllegalArgumentException() {
Calculator calculator = new Calculator();
assertThrows(IllegalArgumentException.class, () ->
calculator.divide(1,0));
}
Función Lambda
3. Test para probar excepciones
Se puede comprobar si se lanza una determinada Exception o si no se ha
lanzado ninguna
@Test
@DisplayName("No lanza una exception")
public void fraccionNoLanzaUnaException(){
assertDoesNotThrow( () -> new Fraccion(3, 0));
}
Verifica si no se lanza una Exception
@Test
@DisplayName("Lanza una exception")
public void fraccionLanzaUnaException(){
assertThrows(IllegalArgumentException.class, () -> new Fraccion(3, 0));
}
4. Test con restricciones de tiempo. TimeOut
Este test hace uso de funciones Lambda
@Test
void test_timeout_fail() {
// assertTimeout(Duration.ofSeconds(5), () -> delaySecond(10)); // this will fail
assertTimeout(Duration.ofSeconds(5), () -> delaySecond(1)); // pass
}
void delaySecond(int second) {
try {
TimeUnit.SECONDS.sleep(second); Función Lambda
} catch (InterruptedException e) {
e.printStackTrace();
}
}
4. Test con restricciones de tiempo. TimeOut
Este test hace uso de funciones Lambda
@Test
void returnValueBeforeTimeoutExceeded() {
final String message = assertTimeout(Duration.ofMillis(50), () -> {
Thread.sleep(100); // this will fail
//Thread.sleep(49); // pass
return "a message";
}); Función Lambda
assertEquals("a message", message);
}
5. Test parametrizado de JUnit 5. Ejemplos
Test parametrizado con @ValueSource
@ParameterizedTest
@DisplayName("EsPrimo lista con números
primos")
@ValueSource(ints = {2, 3, 5, 7, 11, 13,
Integer.MAX_VALUE})
void esPrimoListaConNumerosPrimos(int number) {
assertTrue(Ejercicios.esPrimo(number));
}
5. Test parametrizado de JUnit 5. Ejemplos
Test parametrizado con @CsvSource
@ParameterizedTest
@DisplayName("EsPrimo lista de casos de prueba")
@CsvSource({
"1,false",
"2,true",
"3,true",
"4,false"
})
void esPrimoListaCasosDePrueba(int num, boolean expected) {
boolean result = Ejercicios.esPrimo(num);
assertEquals(expected, result);
}
5. Test parametrizado de JUnit 5. Ejemplos
Test parametrizado con @CsvSource
@ParameterizedTest
@CsvSource({
"10, 3, 3.333, 0.001",
"4, 2, 2, 0.01",
"12, 5, 2.4, 0.1",
"7, 3, 2.3, 0.01" //fail
})
@DisplayName("Division lista casos de prueba")
public void divisionParametrizedTest(double ope1, double ope2, double expected, double delta){
double result = Calculadora.division(ope1, ope2);
assertEquals(expected, result, delta);
}
5. Test parametrizado de JUnit 5. Ejemplos
Test parametrizado con @CsvFileSource
@ParameterizedTest
@CsvFileSource(resources = "/data.csv", numLinesToSkip = 1)
@DisplayName("Division lista casos de prueba desde un fichero csv")
public void divisionParametrizedTestCSVFile(double ope1, double ope2, double
expected, double delta){
double result = Calculadora.division(ope1, ope2); data.csv
assertEquals(expected, result, delta);
} ope1, ope2, expected,
delta
10, 3, 3.333, 0.001
4, 2, 2, 0.01
12, 5, 2.4, 0.1
7, 3, 2.3, 0.01
5. Test parametrizado de JUnit 5. Ejemplos
Test parametrizado con @MethodSource
@ParameterizedTest
@DisplayName("EsPrimo lista de primos con MethodSource")
@MethodSource("proveeCasosPrueba")
void esPrimoParametrizedMethodSource(int num, boolean expected){
boolean result = Ejercicios.esPrimo(num);
assertEquals(expected, result);
}
private static Stream<Arguments> proveeCasosPrueba() {
return Stream.of(
Arguments.of(2, true),
Arguments.of(3, true),
Arguments.of(5, true),
Arguments.of(4, false)
);
}
5. Test parametrizado de JUnit 5. Ejemplos
Test parametrizado con @MethodSource usando objetos
@ParameterizedTest
@DisplayName("Suma Fracciones Test Parametrizado")
@MethodSource("proveeCPFracciones")
void sumaFraccionesParametrizado(Fraccion fr1, Fraccion fr2, Fraccion expected){
Fraccion result = fr1.sumar(fr2);
assertEquals(expected, result);
}
private static Stream<Arguments> proveeCPFracciones() {
return Stream.of(
Arguments.of(new Fraccion(2,3), new Fraccion(1,5), new Fraccion(13,15)),
Arguments.of(new Fraccion(-2,3), new Fraccion(1,5), new Fraccion(-7,15)),
Arguments.of(new Fraccion(2,3), new Fraccion(1,-5), new Fraccion(7,15)),
Arguments.of(new Fraccion(2,3), new Fraccion(2,10), new Fraccion(13,15))
);
}
5. Test parametrizado de JUnit 5. Ejemplos
Test parametrizado con @MethodSource usando objetos
@ParameterizedTest
@MethodSource("stringIntAndListProvider")
public void stringLength5AndIntBetween1And2(String str, int num, List<String>
list){
assertEquals(5, str.length());
assertTrue(num >= 1 && num <= 2);
assertEquals(2, list.size());
}
static Stream<Arguments> stringIntAndListProvider() {
return Stream.of(
Arguments.of("apple", 1, Arrays.asList("a", "b")),
Arguments.of("lemon", 2, Arrays.asList("x", "y"))
);
}
6. API Extension
❖ APIExtensions son una característica que permite extender y
personalizar el comportamiento del motor de pruebas JUnit
❖ APIExtension es una interfaz que permite agregar
funcionalidad adicional al motor de pruebas
❖ Se utilizan para realizar tareas adicionales antes o después
de la ejecución de las pruebas, como inicializar o limpiar el
estado de la aplicación o ejecutar pruebas adicionales T
❖ Permiten agregar anotaciones personalizadas a los casos de
prueba, lo que puede ayudar a organizar y categorizar los
casos de prueba
6. API Extension
❖ Para utilizar una APIExtension en JUnit 5, se
debe agregar una dependencia de la extensión y
luego usar la anotación @ExtendWith para
declarar la extensión en la clase de prueba
❖ Como ejemplo vamos a crear un nuevo paquete en
el paquete de pruebas llamado apiextension y
allí vamos a añadir una clase denominada
LifeCycleExtension que implementará varios
interfaces
❖ Finalmente añadiremos a una clase @FraccionTest
la anterior clase usando
@ExtendWith(LifeCycleExtension.class)
6. API Extension
public class LifeCycleExtension implements BeforeAllCallback, BeforeEachCallback, AfterAllCallback,
AfterEachCallback {
@Override
APIExtension
public void afterAll(ExtensionContext extensionContext) throws Exception {
System.out.println("afterAll");
}
@Override
public void afterEach(ExtensionContext extensionContext) throws Exception {
System.out.println("afterEach");
}
@Override
public void beforeAll(ExtensionContext extensionContext) throws Exception {
System.out.println("beforeAll");
}
@Override
public void beforeEach(ExtensionContext extensionContext) throws Exception {
System.out.println("beforeEach");
}
6. API Extension
APIExtension
import static org.junit.jupiter.api.Assertions.*;
@ExtendWith(LifeCycleExtension.class)
class FraccionTest {
...
}
7. Suites y filtros
❖ Imagina que tienes cientos de Test en un proyecto y
necesitas ejecutar un grupo o todos los Test, además
piensa que normalmente se trabaja en un equipo y cada
miembro debe realizar sus propios Test
❖ Un Test Suite permite agrupar y organizar los distintos
Test que se realizan en un proyecto
❖ Se pueden seleccionar Test por paquetes, clases,
etiquetas, ficheros, URIs, Directorios, Módulos, etc
❖ Aquí solo probaremos paquetes, clases y etiquetas
7. Suites y filtros. Selección por paquetes
Crea un nuevo paquete llamado Suite y añade una clase que se
llame AllSuites. Seleccionamos todos los test de un paquete:
package org.ieszaidinvergeles.dam.suite;
import org.junit.platform.suite.api.SelectPackages;
import org.junit.platform.suite.api.Suite;
import org.junit.platform.suite.api.SuiteDisplayName;
@Suite
@SuiteDisplayName("Todos los test seleccionando el paquete
principal")
@SelectPackages("org.ieszaidinvergeles.dam")
public class AllSuites {
}
7. Suites y filtros. Selección por clases
Seleccionamos por clase usando @SelecClasses
package org.ieszaidinvergeles.dam.suite;
import org.ieszaidinvergeles.dam.*;
import org.junit.platform.suite.api.*;
@Suite
@SuiteDisplayName("Seleccionando por clases..")
@SelectClasses({FraccionTest.class, CalculadoraTest.class})
public class AllSuites { }
7. Suites y filtros. Selección por etiquetas
Para hacer esta selección debemos “marcar” los métodos de
prueba con @Tag("etiqueta")
package org.ieszaidinvergeles.dam.suite;
import org.junit.platform.suite.api.*;
@Suite
@SuiteDisplayName("Seleccionando test usando etiquetas")
@SelectPackages("org.ieszaidinvergeles.dam")
@IncludeTags("fraccion")
public class AllSuites {}
@Tag("fraccion") FraccionTest.java
@ParameterizedTest
@DisplayName("Suma Fracciones Test Parametrizado")
@MethodSource("proveeCPFracciones")
void sumaFraccionesParametrizado(Fraccion fr1, Fraccion fr2, Fraccion expected) {
8. Ordenar test
❖ En JUnit 5 permite establecer el orden de ejecución de
los test de prueba
❖ Para ello se usa la anotación @TestMethodOrder
8. Ordenar test
Vamos a probar @TestMethodOrder
@ExtendWith(LifeCycleExtension.class)
@TestMethodOrder(value = MethodOrderer.OrderAnnotation.class)
public class FraccionTest {
@Test
@Order(2)
@Disabled("Not implemented")
void restar() {}
@Test
@Order(1)
@Disabled("Not implemented")
void multiplicar() {}
...
9. AssertJ
❖ AssertJ es una biblioteca de aserciones (assertions)que facilita la
escritura de pruebas unitarias más legibles y expresivas.
❖ Esta biblioteca proporciona una serie de métodos de aserción que
permiten escribir pruebas más claras, concisas y fáciles de entender
❖ La sintaxis de AssertJ es muy legible, por ejemplo, en lugar de usar los
métodos assertEquals o assertTrue de JUnit, se pueden utilizar los
métodos AssertJ para expresar las aserciones de una forma más natural y
legible. Por ejemplo:
// Usando JUnit
assertEquals(3, myList.size());
// Usando AssertJ
assertThat(myList).hasSize(3);
9. AssertJ
Para poder usarla debemos añadir la dependencia siguiente
al fichero .pom del proyecto
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.24.2</version>
<scope>test</scope>
</dependency>
AssertJ ofrece una amplia gama de funcionalidades para
aserciones, como aserciones para objetos, colecciones,
fechas, expresiones regulares, excepciones y muchas otras
9. AssertJ
Para poder usarla debemos añadir la dependencia siguiente
al fichero .pom del proyecto
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.24.2</version>
<scope>test</scope>
</dependency>
9. AssertJ. Ejemplos
Probar los distintos valores de un objeto
@Test
void personaTest(){
Persona persona = new Persona("Juan", 30, "[email protected]");
// Comprobar que los valores son correctos
assertThat(persona)
.hasFieldOrPropertyWithValue("nombre", "Juan")
.hasFieldOrPropertyWithValue("edad", 30)
.hasFieldOrPropertyWithValue("email", "
[email protected]");
}
9. AssertJ. Ejemplos
Test parametrizado
@ParameterizedTest
@ValueSource(ints = {2, 4, 6, 8, 10})
void testEsPar(int numero) {
assertThat(numero).isInstanceOf(Integer.class); // Comprobar
que el valor de entrada es un entero
assertThat(esPar(numero)).isTrue(); // Comprobar que el
resultado es verdadero
}
9. AssertJ. Ejemplos
Test para comprobar que se lanza una excepción
@Test
void testDividirPorCero() {
int dividendo = 10;
int divisor = 0;
// Comprobar que se lanza una excepción al dividir por cero
assertThatThrownBy(() -> dividir(dividendo,
divisor)).isInstanceOf(ArithmeticException.class);
}
9. AssertJ. Ejemplos
Test parametrizado
@ParameterizedTest
@ValueSource(ints = {2, 4, 6, 8, 10})
void testEsPar(int numero) {
assertThat(numero).isInstanceOf(Integer.class); // Comprobar
que el valor de entrada es un entero
assertThat(esPar(numero)).isTrue(); // Comprobar que el
resultado es verdadero
}
9. AssertJ. Ejemplos
Test parametrizado usando objetos
@ParameterizedTest
@MethodSource("fraccionProvider")
void testSuma(Fraccion fraccion1, Fraccion fraccion2, Fraccion expected) {
fraccion1 = fraccion1.sumar(fraccion2); // Calculamos la suma de las dos fracciones
assertThat(fraccion1).isEqualTo(expected); // Comprobamos que el resultado de la suma es el
esperado
}
private static Stream<Arguments> fraccionProvider() {
return Stream.of(
Arguments.of(new Fraccion(1, 2), new Fraccion(1, 2), new Fraccion(1, 1)),
// 1/2 + 1/2 = 1/1
Arguments.of(new Fraccion(1, 3), new Fraccion(1, 3), new Fraccion(2, 3)),
// 1/3 + 1/3 = 2/3
Arguments.of(new Fraccion(2, 3), new Fraccion(1, 3), new Fraccion(1, 1))
// 2/3 + 1/3 = 1/1
);
}
class LyfecicleTest {
@BeforeAll
10. Ciclo de vida de un Test static void initAll() {
}
@BeforeEach
void init() {
}
Ciclo de vida @Test
void regular_testi_method() {
...
}
@Test
@Disabled("este tests no se ejecuta")
void skippedTest() {
// not executed
}
@AfterEach
void tearDown() {
}
@AfterAll
static void tearDownAll() {
}
}
10. Ciclo de vida: Anotaciones @AfterEach y @AfterAll
@AfterEach y @AfterAll
@ParameterizedTest
@
FIN