La Pirámide de Testing: Rápido, Confiable, Barato
Un bug detectado en desarrollo cuesta minutos de corrección. El mismo bug en producción cuesta reputación y miles de dólares. La pirámide define la proporción ideal de pruebas para detectar errores lo antes posible.
Muchos tests E2E frágiles que tardan horas en correr y suites de integración tan pesadas que nadie las ejecuta localmente. El feedback llega tarde y el equipo deja de confiar en los tests.
Arrange, Act, Assert: La Anatomía de un Test
Cada test responde a una única pregunta y se estructura en 3 fases: preparar el escenario, ejecutar la acción exacta que se quiere probar, y verificar el resultado.
Se instancia la clase bajo prueba y se preparan los argumentos.
Calculadora calc = new Calculadora();
int a = 5;
int b = 10; Una única llamada: la acción exacta que el test verifica.
int resultado = calc.sumar(a, b); Se compara el valor esperado contra el valor obtenido.
assertEquals(15, resultado); Cada instancia es nueva: un test no puede contaminar el estado del siguiente.
Mocks con Mockito: Aislar sin Tocar el Mundo Real
Probar PedidoService no debería conectarse a la pasarela de pagos real ni cobrar dinero de verdad. Un mock es un doble controlado que responde exactamente como se le indique.
when(pasarela.cobrar(pedido))
.thenReturn(true); Su lógica de negocio se ejecuta tal cual; solo sus colaboradores externos son dobles.
verify(pasarela, times(1)).cobrar(pedido); when(inventario.hayStock(sku))
.thenReturn(true); Controller, Service, Repository: Separar Responsabilidades
Un microservicio REST separa estrictamente la traducción HTTP/JSON, las reglas de negocio y la persistencia. La inyección de dependencias por constructor es lo que hace testeable cada capa por separado.
Recibe @RequestBody ProductoDTO, valida la entrada y devuelve un ResponseEntity.
Aplica reglas de precios, descuentos y validaciones de dominio puras.
Comunica con la base de datos vía SQL / Hibernate / JPA.
public class ProductoController {
ProductoService service =
new ProductoServiceImpl();
} public class ProductoController {
private final ProductoService service;
ProductoController(ProductoService service) {
this.service = service;
}
} El Ciclo de Vida de una Petición REST
Traza completa de un POST /productos con payload JSON, desde el cliente hasta el disco y de vuelta.
POST /productos { "nombre": "Café", "precio": 3.5 } - 1 Petición HTTP entrante
El cliente envía el JSON en el cuerpo de la petición POST.
- 2 Jackson → ProductoDTO
Jackson deserializa el JSON en un objeto Java ProductoDTO.
- 3 Controller → Service
productoService.crear(dto): el Controller delega en el Service. - 4 Reglas de negocio
El Service calcula impuestos y transforma el DTO en la entidad de dominio Producto.
- 5 Persistencia
INSERT INTO productos ...: el Repository guarda la entidad en la base relacional. - 6 HTTP 201 Created
El Controller empaqueta la respuesta con el header Location del nuevo recurso.