Pruebas en Java: desde pruebas unitarias hasta pruebas de extremo a extremo
Las pruebas de calidad son la base de un software confiable. En el mundo de Java existe una pirámide de pruebas bien establecida que incluye tres niveles principales: unit (pruebas unitarias), integration (pruebas de integración) y e2e (pruebas de extremo a extremo). En este artículo analizaremos cada uno de ellos, proporcionaremos ejemplos prácticos en Java y explicaremos cómo construir correctamente una estrategia de pruebas en su proyecto.
1. Pruebas unitarias: la base de la pirámide
Las pruebas unitarias verifican componentes individuales del programa de forma aislada, generalmente una clase o método. Se ejecutan rápidamente, no requieren dependencias externas (BD, API) y deben cubrir la mayor parte de la lógica de negocio.
Herramientas para pruebas unitarias en Java
- JUnit 5 — framework estándar para escribir pruebas.
- Mockito — biblioteca para crear objetos mock.
- AssertJ — aserciones fluidas para verificaciones legibles.
Ejemplo de prueba unitaria con JUnit 5 y Mockito
Supongamos que tenemos un servicio OrderService que depende de PaymentGateway. Queremos probar la lógica de cálculo de descuento sin llamar a la pasarela de pago real.
// Clase a probarpublic class OrderService { private final PaymentGateway paymentGateway;
public OrderService(PaymentGateway paymentGateway) { this.paymentGateway = paymentGateway; }
public double calculateDiscount(double amount) { if (amount > 1000) { return amount * 0.1; // 10% de descuento } return 0; }}
// Prueba unitariaimport org.junit.jupiter.api.Test;import org.junit.jupiter.api.extension.ExtendWith;import org.mockito.InjectMocks;import org.mockito.Mock;import org.mockito.junit.jupiter.MockitoExtension;import static org.junit.jupiter.api.Assertions.assertEquals;
@ExtendWith(MockitoExtension.class)public class OrderServiceTest {
@Mock private PaymentGateway paymentGateway;
@InjectMocks private OrderService orderService;
@Test public void testCalculateDiscount_AmountAbove1000_Returns10Percent() { double result = orderService.calculateDiscount(1500); assertEquals(150.0, result, 0.001); }
@Test public void testCalculateDiscount_AmountBelow1000_ReturnsZero() { double result = orderService.calculateDiscount(500); assertEquals(0.0, result); }}Mejores prácticas: use @BeforeEach para inicializar datos comunes, evite probar métodos privados directamente, siga la regla de "una verificación por prueba".
2. Pruebas de integración: verificación de la interacción
Las pruebas de integración verifican cómo varios módulos funcionan juntos, por ejemplo, la interacción de un servicio con una base de datos, colas de mensajes o API externas. A diferencia de las pruebas unitarias, aquí se utilizan dependencias reales o en memoria.
Herramientas para pruebas de integración
- Spring Boot Test — para probar aplicaciones Spring.
- Testcontainers — para levantar contenedores Docker (BD, Kafka).
- H2 Database — base de datos en memoria para pruebas rápidas.
Ejemplo de prueba de integración con Spring Boot
Probamos un controlador REST con conexión real a la BD (en la prueba usamos H2).
// Controlador@RestController@RequestMapping("/api/users")public class UserController { private final UserRepository userRepository;
public UserController(UserRepository userRepository) { this.userRepository = userRepository; }
@GetMapping("/{id}") public User getUser(@PathVariable Long id) { return userRepository.findById(id) .orElseThrow(() -> new Runti