«Tenemos tests», dice el equipo. Y es verdad: 3.000 tests, 40 minutos de suite, siete que fallan aleatoriamente los martes y una cobertura del 85% que no impide que los bugs lleguen a producción igualmente. El problema casi nunca es la cantidad de tests: es dónde están puestos.
La pirámide de testing — la idea que Mike Cohn popularizó hace veinte años — sigue siendo la mejor respuesta que tenemos a esa pregunta. Esta guía la explica con el nivel de detalle que usamos en HexagonalGuru al montar (o rescatar) la estrategia de pruebas de un proyecto real.
La Pirámide
Tres capas, cada una con su trabajo:
- Unitarios (la base, ~70%). Prueban una unidad aislada: una entidad, un value object, un caso de uso con sus dependencias simuladas. Sin base de datos, sin HTTP, sin framework. Corren en milisegundos.
- Integración (el medio, ~20%). Prueban que las piezas encajan con la infraestructura real: el repositorio contra una base de datos de verdad, el adaptador HTTP contra el router, el cliente de la API externa contra un sandbox.
- E2E (la cima, ~10%). Prueban el sistema completo como lo haría un usuario: login, flujo de compra, checkout. Navegador real, todo el stack levantado. Lentos, frágiles y caros — por eso son pocos y solo para los caminos críticos.
La forma no es decorativa: es la consecuencia directa de tres factores que cambian con cada capa — velocidad (milisegundos → segundos → minutos), precisión del diagnóstico (un unitario roto te dice la línea; un E2E roto te dice «algo falla en el checkout») y coste de mantenimiento (cada refactor rompe E2E por docenas).
Qué Va en Cada Capa (con Ejemplos Reales)
Unitarios: la lógica de negocio
Todo lo que sea una regla de tu dominio vive aquí. Si seguiste nuestra serie de DDD y arquitectura hexagonal, esto te suena: las reglas del núcleo se prueban aisladas, con adaptadores en memoria, sin levantar nada:
public function test_no_se_confirma_un_pedido_vacio(): void
{
$pedido = Pedido::crear(PedidoId::nuevo(), ClienteId::nuevo());
$this->expectException(PedidoVacio::class);
$pedido->confirmar();
}
Este test corre en microsegundos y dice exactamente qué regla se rompió si alguien la toca dentro de dos años. Cientos de estos son la base sólida.
Integración: los bordes
public function test_el_repositorio_guarda_y_recupera_el_agregado(): void
{
$pedido = Pedido::crear(PedidoId::nuevo(), ClienteId::nuevo());
$pedido->anadirLinea(ProductoId::nuevo(), Dinero::euros(19.99), 2);
$this->repositorio->guardar($pedido); // base de datos real (testcontainer)
$recuperado = $this->repositorio->buscar($pedido->id());
self::assertEquals('3998', $recuperado->total()->centimos);
}
Aquí es donde se cazan los errores de mapeo del ORM, las migraciones rotas y las consultas N+1 que el unitario no puede ver.
E2E: solo los caminos que pagan el servidor
Login, registro, compra, el flujo que si se rompe te llama el CEO. Uno o dos por funcionalidad crítica, con datos semilla controlados, y aceptando su coste: son la alarma de incendios, no el detector de humo de cada habitación.
Las Antipirámides: Cómo se Rompe Esto
- El cono de helado (pirámide invertida). Pocos unitarios, muchos E2E. La suite tarda una hora, falla por causas ajenas al código, nadie la ejecuta en local y al final nadie le cree. Es la más común en equipos que «empezaron probando con Selenium».
- El teatro de la cobertura. 90% de cobertura construida con tests sin aserciones, getters probados con orgullo y mutaciones que sobrevivirían a todas las pruebas. La cobertura mide qué líneas se ejecutaron, no qué comportamiento se verificó.
- El unitario que lo mockea todo. Mockeas la base de datos, el repositorio y medio dominio: el test pasa siempre y no prueba nada. Si todo es mock, el test es un poema sobre cómo te gustaría que fuera el código.
- Probar la implementación, no el comportamiento. «Este método privado se llamó dos veces»: refactor inocente, test roto. Los tests deben sobrevivir a los refactors; para eso se prueba el qué, no el cómo.
Errores Comunes
- Empezar la pirámide por arriba. Montar Cypress antes de tener un solo test del dominio. Es construir el tejado primero: impresiona, pero no sostiene nada.
- Tests que dependen del orden o de datos compartidos. Funcionan en secuencial, fallan en paralelo. Cada test crea sus datos y no toca los de nadie.
- La suite lenta como impuesto. Si la suite tarda 40 minutos, se ejecuta una vez al día y los bugs se cazan horas después de escribirlos. La velocidad de la suite es una feature: se presupuesta y se defiende (unitarios en segundos, integración en minutos, E2E aparte).
- Fallos aleatorios tolerados. «Reejecuta y ya pasará» es la muerte de la confianza en la suite. Un test flaky se arregla o se elimina; no hay tercera opción sana.
- Probar solo el camino feliz. Los bugs viven en los bordes: el pedido vacío, el email duplicado, el pago rechazado. Un test de excepción vale por tres de éxito.
Cómo Empezar (o Empezar de Nuevo)
- Identifica los 3 flujos críticos del negocio y escribe un E2E para cada uno. Ya tienes alarma de incendios.
- Pon la lógica de dominio en el núcleo (si no lo está) y cúbrela con unitarios rápidos. Es la capa con mejor retorno por línea escrita.
- Añade integración en los repositorios y adaptadores que tocan infraestructura real.
- Regla de equipo: todo bug arreglado viene con su test de regresión. La suite crece exactamente donde el sistema ha demostrado romperse.
- Mide el tiempo de la suite como una métrica de producto, no como un detalle técnico.
En Resumen
Una buena estrategia de testing no es «más tests»: es cada test en su capa. Muchos unitarios rápidos para la lógica, integración justa en los bordes, pocos E2E para los caminos críticos — y una suite en la que el equipo confía porque es rápida, estable y solo falla cuando algo está roto de verdad. La pirámide no es un dibujo bonito: es la forma de que probar no duela.
¿Tu suite tarda una eternidad, falla por deporte o directamente no existe? En nuestras auditorías de calidad medimos el estado real (velocidad, flakiness, cobertura útil) y te dejamos un plan por capas. Hablemos →
Sigue leyendo: OWASP Top 10 explicado con ejemplos reales — empezando por los tests de autorización que cazan el IDOR.