Java JUnit framework de pruebas unitarias
JUnit es uno de los frameworks de pruebas unitarias más populares en el lenguaje de programación Java, utilizado para escribir y ejecutar pruebas automatizadas repetibles.
JUnit fue creado por Kent Beck y Erich Gamma, y es miembro de la familia xUnit. Las pruebas unitarias son el proceso de verificar y validar la parte más pequeña comprobable del software (generalmente métodos o clases).
Las características principales de JUnit incluyen:
- Proporciona anotaciones para identificar métodos de prueba
- Proporciona aserciones para verificar los resultados esperados
- Admite suites de pruebas (Test Suite)
- Proporciona ejecutores de pruebas (Test Runner)
¿Por qué se necesitan las pruebas unitarias?
Las pruebas unitarias son una parte indispensable del desarrollo de software moderno y aportan los siguientes beneficios:
- Detección temprana de problemas: Permite encontrar y corregir errores durante el desarrollo
- Mejora la calidad del código: Obliga a los desarrolladores a escribir código más modular y comprobable
- Función de documentación: Los propios casos de prueba son la mejor documentación del comportamiento del código
- Red de seguridad para la refactorización: Garantiza que modificar el código no rompa la funcionalidad existente
- Reduce el tiempo de depuración: Localiza rápidamente el origen del problema
Usar JUnit en proyectos
Para JUnit 5:
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.8.2</version>
<scope>test</scope>
</dependency>
Para JUnit 4:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
Fundamentos de JUnit 5
JUnit 5 es la versión más reciente y se compone de tres módulos principales:
- JUnit Platform (la base para ejecutar pruebas)
- JUnit Jupiter (el nuevo modelo de programación y extensión)
- JUnit Vintage (admite la ejecución de pruebas de JUnit 3 y 4)
Anotaciones básicas
Anotaciones de versiones anteriores:
@Test: Marca un método como método de prueba@Before: Se ejecuta antes de cada método de prueba@After: Se ejecuta después de cada método de prueba@BeforeClass: Se ejecuta antes de todas las pruebas (método estático)@AfterClass: Se ejecuta después de todas las pruebas (método estático)@Ignore: Ignora el método de prueba
Ejemplo
public class CalculatorTest {
@BeforeClass
public static void setUpBeforeClass() {
System.out.println("Before all tests");
}
@Before
public void setUp() {
System.out.println("Before each test");
}
@Test
public void testAddition() {
Calculator calculator = new Calculator();
int result = calculator.add(2, 3);
Assert.assertEquals(5, result);
}
@Test
@Ignore("Not implemented yet")
public void testSubtraction() {
// Código de prueba
}
@After
public void tearDown() {
System.out.println("After each test");
}
@AfterClass
public static void tearDownAfterClass() {
System.out.println("After all tests");
}
}
JUnit 5 es la nueva generación, con las siguientes anotaciones nuevas:
@BeforeEachReemplaza@Before@AfterEachReemplaza@After@BeforeAllReemplaza@BeforeClass@AfterAllReemplaza@AfterClass@DisabledReemplaza@Ignore
Ejemplo
@Test
void testMethod() {
// Código de prueba
}
@BeforeEach
void setUp() {
// Se ejecuta antes de cada método de prueba
}
@AfterEach
void tearDown() {
// Se ejecuta después de cada método de prueba
}
@BeforeAll
static void initAll() {
// Se ejecuta una vez antes de todos los métodos de prueba
}
@AfterAll
static void tearDownAll() {
// Se ejecuta una vez después de todos los métodos de prueba
}
Métodos de aserción comunes
JUnit proporciona una gran variedad de métodos de aserción para verificar los resultados de las pruebas:
assertEquals(expected, actual)assertTrue(condition)assertFalse(condition)assertNull(object)assertNotNull(object)assertSame(expected, actual)(Comprueba si es el mismo objeto)assertNotSame(unexpected, actual)assertArrayEquals(expectedArray, actualArray)
Ejemplo
@Test
void testAssertions() {
// Aserción de igualdad
assertEquals(expected, actual);
// Aserción de verdadero
assertTrue(condition);
// Aserción de nulo
assertNull(object);
// Aserción de excepción
assertThrows(ExpectedException.class, () -> {
// Código que lanzará una excepción
});
// Aserción de tiempo de espera
assertTimeout(Duration.ofMillis(100), () -> {
// Código que debe completarse dentro del tiempo especificado
});
}
Escribir tu primera prueba JUnit
Aprendamos a escribir pruebas JUnit con un ejemplo sencillo.
1. Crear la clase bajo prueba
Ejemplo
public int add(int a, int b) {
return a + b;
}
public int divide(int a, int b) {
if (b == 0) {
throw new ArithmeticException("El divisor no puede ser cero");
}
return a / b;
}
}
2. Crear la clase de prueba
Ejemplo
import static org.junit.jupiter.api.Assertions.*;
class CalculatorTest {
private Calculator calculator;
@BeforeEach
void setUp() {
calculator = new Calculator();
}
@Test
void testAdd() {
assertEquals(5, calculator.add(2, 3));
}
@Test
void testDivide() {
assertEquals(2, calculator.divide(6, 3));
}
@Test
void testDivideByZero() {
assertThrows(ArithmeticException.class, () -> {
calculator.divide(1, 0);
});
}
}
Características avanzadas de JUnit
Pruebas parametrizadas
JUnit 5 proporciona la@ParameterizedTestanotación, que permite ejecutar la misma prueba varias veces con diferentes parámetros:
Ejemplo
@ValueSource(ints = {1, 2, 3})
void testWithValueSource(int argument) {
assertTrue(argument > 0 && argument < 4);
}
Ciclo de vida de las pruebas
Comprender el ciclo de vida de las pruebas JUnit es importante para escribir pruebas efectivas:
@BeforeAllEjecución del método (solo una vez)- Para cada método de prueba:
- Crear una instancia de la clase de prueba
@BeforeEachEjecución del método- Ejecución del método de prueba
@AfterEachEjecución del método
@AfterAllEjecución del método (solo una vez)
Suite de pruebas
Se puede utilizar la@Suiteanotación para agrupar varias clases de prueba y ejecutarlas juntas:
Ejemplo
import org.junit.platform.suite.api.Suite;
@Suite
@SelectClasses({CalculatorTest.class, AnotherTest.class})
public class TestSuite {
}
Mejores prácticas
- Nombrado de pruebas: El nombre del método de prueba debe expresar claramente su intención, como
shouldReturnTrueWhenInputIsValid() - Responsabilidad única: Cada método de prueba solo prueba un punto funcional
- Pruebas independientes: No debe haber dependencias entre las pruebas
- Retroalimentación rápida: Mantén las pruebas ejecutándose rápidamente
- Cobertura de pruebas: Busca una cobertura razonable, pero no persigas ciegamente el 100%
- Datos de prueba: Usa datos de prueba significativos
- Evita probar detalles de implementación: Prueba el comportamiento, no la implementación
Preguntas frecuentes
¿Cuál es la diferencia entre JUnit 4 y JUnit 5?
Las principales diferencias incluyen:
- JUnit 5 requiere Java 8 o superior
- Las anotaciones se mueven del paquete
org.junital paqueteorg.junit.jupiter.apiPaquete @Beforey@Aftercambia a@BeforeEachy@AfterEach@BeforeClassy@AfterClasscambia a@BeforeAlly@AfterAll- JUnit 5 introduce un modelo de extensiones para reemplazar las reglas de JUnit 4
¿Cómo ejecutar pruebas JUnit?
Se pueden ejecutar pruebas JUnit de las siguientes maneras:
- Haz clic derecho en la clase o método de prueba en el IDE y selecciona "Ejecutar"
- Usando Maven:
mvn test - Usando Gradle:
gradle test - Usando el lanzador de consola de JUnit
¿Cómo probar métodos privados?
Generalmente no se recomienda probar directamente los métodos privados, sino probarlos indirectamente a través de métodos públicos. Si es necesario probar métodos privados, se puede considerar:
- Usar reflexión
- Cambiar el método a paquete privado (sin modificador) y crear una clase de prueba con la misma estructura de paquete en el directorio de pruebas
- Refactorizar el código para extraer la lógica del método privado a una clase separada
Resumen
JUnit es una herramienta de pruebas imprescindible para los desarrolladores de Java. Dominarla puede mejorar significativamente la calidad del código y la eficiencia del desarrollo. Comienza con pruebas unitarias simples y aprende gradualmente características más avanzadas, como pruebas parametrizadas, suites de pruebas, etc. Recuerda que las buenas pruebas deben recibir la misma importancia que el código de producción; mantener el código de prueba limpio y mantenible es igualmente importante.
Otras extensiones
Bibliotecas comunes de Java