Curso exprés · No. 21
Un test no es más que código que comprueba tu código, automáticamente. La gente cree que su trabajo es probar que el código de hoy funciona — pero la verdadera recompensa llega después: los tests son lo que te deja cambiar, refactorizar y añadir funciones mañana sin romper lo que ya funcionaba. Aprende los tipos y el vocabulario, y testear deja de ser una carga para convertirse en lo que te permite ir rápido.
19 conceptos · un diagrama para cada uno · chuleta al final
Casi todo el mundo malinterpreta para qué sirven los tests. Parecen una forma de probar que el código funciona; su verdadero valor es algo más profundo y más práctico — y verlo cambia cómo los escribes.
El mapa: 19 conceptos en siete capítulos
Un mapa de metro: primero ves todas las líneas de golpe, luego recorres estación por estación.
Cada concepto del curso está en uno de siete capítulos. Primero, por qué existen los tests. Luego, los tipos de test y cómo equilibrarlos. Luego, los falsos que necesitas para aislar un trozo de código. Después: el oficio de un buen test, confiar en el conjunto de tests y ponerlo todo a trabajar.
Cómo leer este curso
Un pasaporte: los mismos campos para todos, así es fácil compararlos.
Cada concepto recibe el mismo trato: su nombre en inglés (recuérdalo — es el término que encontrarás en la documentación y en las entrevistas), una imagen de la vida real, un diagrama y una tarjeta con campos: problema, idea, ejemplo, coste, cuándo usarlo y conceptos relacionados. Una idea recorre todo el curso: los tests son un seguro para los cambios futuros, no un certificado de que el código funcionó una vez.
Automated Test — código que comprueba código
Una segunda persona que rehace tus cuentas en una calculadora y marca las que no cuadran — automática, incansable e idéntica cada vez.
Un test es un trozo pequeño de código que ejecuta tu código con una entrada conocida y comprueba que el resultado es el que esperas. «Dado 2 y 3, ¿add devuelve 5?» Si sí, el test passes; si no, fails y te lo dice. Esa es toda la mecánica. Lo potente es que es automático y repetible — puedes ejecutar miles de estas comprobaciones en segundos, cada vez que cambias algo, sin que un humano vuelva a verificar a mano.
- Problema
Comprobar a mano es lento y aburrido — así que tras cada cambio nadie vuelve a comprobarlo todo.
- Idea
Escribe la comprobación como código: entrada conocida → llamada → comparar con lo esperado. Resultado: pasa o falla.
- Ejemplo
«
add(2, 3)debe devolver 5» — una línea, se ejecuta en milisegundos.- Coste
Los tests también son código: hay que escribirlos, leerlos y mantenerlos.
- Cuándo usarlo
- Para cualquier código que vayas a seguir cambiando.
- Relaciones
Caza Regressions; viene como Unit, Integration y E2E; se ejecuta en el CI Gate.
Safety Net — lo importante es cambiar sin miedo
El arnés de seguridad de un escalador: no hace la escalada por ti, pero te deja intentar un movimiento audaz porque un resbalón no será fatal. Escalas con más fuerza porque, si caes, te sujeta.
Aquí está el malentendido. Los tests no van sobre todo de probar que el código de hoy es correcto — van sobre mañana. Cuando cambias código, lo refactorizas o añades una función, un buen conjunto de tests (test suite) te dice al instante si rompiste algo que antes funcionaba. Esa red de seguridad es lo que te deja cambiar una base de código grande con confianza en lugar de tener miedo de tocar nada. Los tests son cómo sigues yendo rápido sin que las cosas se rompan en silencio a tu espalda.
Regression — cuando un cambio rompe lo que funcionaba
Una hilera de hilos trampa por toda una casa: en el momento en que algo perturba una habitación que ni siquiera mirabas, salta una alarma — no tienes que patrullar cada habitación tú mismo.
Una regression es cuando un cambio rompe algo que antes funcionaba — a menudo en un sitio lejano a lo que tocaste. Sin tests, las regressions se esconden hasta que un usuario las encuentra. Con tests, en el momento en que tu cambio rompe un comportamiento viejo, un test se pone en rojo y lo señala, justo ahí. Esta es la recompensa del día a día: haces un cambio, ejecutas los tests y sabes al instante si también rompiste algo en otra parte. El conjunto vigila toda la casa mientras tú trabajas en una habitación.
- Qué es
- Un cambio rompe un comportamiento que antes funcionaba.
- Trampa
A menudo se rompe lejos de donde editaste, en una parte distante del sistema.
- Ejemplo
Cambiaste el total del carrito — y las facturas empezaron a mostrar un importe incorrecto.
- Cómo cazarla
Un conjunto de tests sobre el comportamiento antiguo, ejecutado en cada cambio.
- Consejo
- ¿Encontraste un bug? Añade un test para que nunca vuelva.
- Relaciones
La caza un Automated Test; la vigila automáticamente el CI Gate.
Un test comprueba el código automáticamente. Su verdadero valor no es una prueba puntual — es la libertad de cambiar mañana sin romper en silencio lo que funciona hoy.
El cimiento del testing es el unit test: una comprobación rápida y enfocada de una pieza pequeña de código por sí sola. La mayoría de tus tests serán estos, y con razón.
Unit Test — una pieza pequeña en aislamiento
Comprobar que una sola pieza de Lego tiene la forma y el tamaño correctos antes de construir con ella — no montar el castillo entero para descubrir que una pieza estaba mal.
Un unit test comprueba una unidad pequeña — normalmente una sola función — en aislamiento del resto del sistema. Le das una entrada, compruebas su salida, nada más involucrado. Como la pieza es pequeña e independiente, cuando el test falla sabes exactamente qué se rompió y dónde. Los unit tests son el microscopio del testing: estrechos, precisos y apuntados a una sola cosa a la vez.
- Problema
Cuando falla una comprobación grande, no sabes cuál de cien partes tiene la culpa.
- Idea
Comprueba una función cada vez, aislada de la base de datos, la red y todo lo demás.
- Ejemplo
calculateTax(100)devuelve20— sin base de datos, sin HTTP, en milisegundos.- Coste
No ve cómo funcionan juntas las piezas — de eso se encargan otros tests.
- Cuándo usarlo
Para la mayoría de tus tests: lógica de negocio, cálculos, reglas, casos límite.
- Relaciones
La base de la Test Pyramid; se aísla con Test Doubles; tiene la forma Arrange–Act–Assert.
Rápidos y muchos — esa es toda la idea
Un corrector ortográfico que escanea el documento entero en un parpadeo — tan rápido que lo ejecutas constantemente, no una revisión lenta que haces una vez al mes.
Como cada unit test es diminuto y no toca nada externo, corre en milisegundos — así que puedes tener miles y ejecutarlos todos en cada cambio, constantemente. Esa velocidad es el punto: un conjunto de tests que puedes ejecutar en segundos se ejecuta todo el tiempo, cazando roturas en el instante en que ocurren. Un conjunto lento se salta, y un conjunto que se salta no protege nada. Rápidos y abundantes es lo que hace de los unit tests el caballo de batalla.
Arrange–Act–Assert — preparar, actuar, comprobar
Un experimento sencillo: preparas las condiciones, haces la única acción y luego compruebas el resultado. Preparación clara, un movimiento, una verificación.
Un buen unit test tiene tres pasos simples — el patrón Arrange–Act–Assert (AAA): prepara las entradas, llama una sola vez a lo que pruebas y luego afirma (assert) que el resultado es el esperado. Una assertion es la comprobación en sí — «la respuesta debe ser igual a 5.» Mantener los tests en esta forma limpia los hace legibles y hace evidente un fallo. Un test difícil de leer es uno en el que nadie confiará ni querrá mantener.
- Problema
Un test enredado: preparación, llamadas y comprobaciones mezcladas — no se ve qué verifica.
- Idea
Tres bloques en orden: preparación → una acción → comprobación (assertion).
- Ejemplo
Arrange: un carrito con dos artículos. Act:
cart.total(). Assert: el total es igual a 20.- Coste
- Casi ninguno — solo la disciplina de una acción por test.
- Cuándo usarlo
- Siempre, en todo test — unit, integration o end-to-end.
- Relaciones
Hace legible un test — y por tanto Living Documentation; la columna vertebral de un Unit Test.
Un unit test comprueba una pieza pequeña en aislamiento, en milisegundos — así ejecutas miles constantemente. Prepara la entrada, actúa una vez, afirma el resultado.
Los unit tests comprueban las piezas por separado, pero el software son piezas trabajando juntas. Dos tipos de test más amplios cubren eso — y el equilibrio justo entre los tres tiene una forma que merece conocerse.
Integration Test — piezas trabajando juntas
Después de comprobar cada pieza de Lego, encajas unas cuantas para asegurarte de que de verdad se conectan — las piezas estaban bien por separado, pero ¿encajan?
Un integration test comprueba que varias partes funcionan correctamente juntas — tu código hablando con la base de datos, dos servicios intercambiando datos. Cada unidad puede ser perfecta por separado y aun así no conectar: un formato que no coincide, una suposición equivocada sobre el otro lado. Los integration tests cazan justo esas costuras (seams). Son más lentos que los unit tests porque intervienen más piezas reales en movimiento, pero verifican las uniones que los unit tests, por diseño, se saltan.
- Problema
- Cada parte pasa sus unit tests, pero juntas no funcionan.
- Idea
- Ejecuta varias partes reales juntas y comprueba la unión entre ellas.
- Ejemplo
Un repositorio escribe un usuario en una base de datos de prueba real y lo lee de vuelta.
- Coste
Más lento que los unit tests; necesita un entorno montado (base de datos, servicios).
- Cuándo usarlo
Para las costuras: código ↔ base de datos, servicio ↔ servicio, tu código ↔ una API de terceros.
- Relaciones
La capa intermedia de la Test Pyramid; caza lo que oculta el Over-mocking.
End-to-End Test — todo el sistema, como un usuario
Un ensayo general de toda la obra, de principio a fin, en el escenario real — no solo las frases o el atrezo, sino la función entera tal como la verá el público.
Un end-to-end test (E2E) maneja todo el sistema como lo haría un usuario real — pulsa el botón, rellena el formulario, comprueba que pasó lo correcto en toda la pila. Es el test más realista y la confirmación más valiosa de que el producto realmente funciona. Pero también es el más lento y el más frágil: muchas partes deben estar en marcha a la vez, y un pequeño cambio de interfaz puede romperlo. Usas los e2e tests para unos pocos recorridos críticos, no para todo.
- Problema
Cada parte está probada, pero nadie sabe si el producto funciona como un todo.
- Idea
Recorre el camino de un usuario por toda la pila real y comprueba el resultado.
- Ejemplo
Un robot de navegador: inicia sesión, añade un artículo al carrito, paga, ve «pedido realizado».
- Coste
El más lento y el más frágil; se rompe con pequeños cambios de interfaz.
- Cuándo usarlo
Para pocos recorridos críticos: inicio de sesión, pago, el flujo principal.
- Relaciones
La punta de la Test Pyramid; con demasiados te sale el cono de helado.
Test Pyramid — el equilibrio justo
Una pirámide se sostiene porque su base es ancha y su punta estrecha — ponla del revés sobre la punta y se cae. La forma misma es la estabilidad.
La test pyramid es la regla práctica del equilibrio: muchos unit tests rápidos en la base, menos integration tests en el medio y un puñado de end-to-end tests lentos arriba. Esta forma te da una cobertura amplia y rápida a bajo coste, con justo los checks realistas necesarios en la cima. El antipatrón — muchos e2e tests lentos y pocos unit tests — es el cono de helado (ice-cream cone), y es lento, inestable y doloroso. Apunta a la pirámide, no al cono.
- Problema
Hay muchos tests, pero el conjunto es lento e inestable — así que la gente deja de ejecutarlo.
- Idea
- Muchos tests baratos y rápidos abajo, pocos caros y lentos arriba.
- Ejemplo
Miles de unit tests, cientos de integration tests, una docena de e2e para los flujos principales.
- Coste
- Hay que decidir a conciencia qué nivel comprueba cada cosa.
- Antipatrón
- Ice-cream cone — la pirámide al revés: muchos e2e, pocos unit.
- Relaciones
Las capas son Unit, Integration, E2E; los e2e de más engendran Flaky Tests.
Los unit tests comprueban las piezas por separado, los integration tests las comprueban juntas, los e2e tests comprueban todo el sistema como un usuario. Mantén la pirámide: muchos rápidos, pocos lentos.
Para probar una pieza en aislamiento, a menudo tienes que sustituir las cosas reales de las que depende. Eso son los mocks y los stubs — y son tan fáciles de usar mal como útiles.
Test Double — un falso en lugar de la dependencia real
Un simulador de vuelo en vez de un avión real: instrumentos y vistas falsos te dejan practicar la habilidad con seguridad, sin el coste ni el riesgo de volar de verdad.
Para probar una pieza en aislamiento, sustituyes sus dependencias reales — una base de datos, un servicio de pagos, un envío de correo — por falsos que hacen su papel. El nombre general de cualquiera de esos falsos es test double, como un doble de acción en una película. Esto te permite probar tu código sin la cosa real, que es lenta, cara o impredecible. No quieres que un unit test cobre una tarjeta de verdad o envíe un correo; metes un falso que finge hacerlo, y así el test sigue siendo rápido, fiable y autocontenido.
- Problema
Las dependencias reales son lentas, cuestan dinero o se comportan de forma impredecible — los tests que las usan son frágiles.
- Idea
Sustituye por un objeto que se comporta como la dependencia, pero solo finge.
- Ejemplo
- En lugar de Stripe, un falso que siempre responde «pago realizado».
- Coste
- Un falso puede mentir: la cosa real puede comportarse de otra manera.
- Cuándo usarlo
Para cosas externas, lentas o aleatorias: red, pagos, correo, hora.
- Relaciones
Dos tipos principales — Stub y Mock; da aislamiento a un Unit Test; si te pasas, es Over-mocking.
Stub vs Mock — respuesta enlatada vs llamada comprobada
Un stub es un recortable de cartón que dice una frase cuando le toca; un mock es un actor que además te informa exactamente de lo que le dijiste y cómo.
Se confunden dos tipos de falso. Un stub simplemente devuelve una respuesta fija, enlatada — «finge que la base de datos devuelve este usuario» — para que pruebes cómo maneja tu código esa entrada. Un mock también verifica la interacción — «comprueba que mi código llamó a sendEmail exactamente una vez, con esta dirección.» Un stub alimenta a tu código; un mock vigila cómo se comporta tu código hacia él. Usa un stub para suministrar datos, un mock para afirmar que ocurrió un efecto secundario.
- Qué es
- Un falso que devuelve una respuesta preparada.
- Ejemplo
getUser()siempre devuelve{ name: 'Ann' }.- Qué compruebas
- La salida de tu código con esos datos.
- Cuándo usarlo
- Cuando tu código necesita recibir algo de una dependencia.
- Qué es
- Un falso que registra las llamadas y te deja verificarlas.
- Ejemplo
Comprobar que
sendEmailse llamó exactamente una vez, con la dirección correcta.- Qué compruebas
La propia llamada: si ocurrió, cuántas veces, con qué argumentos.
- Cuándo usarlo
Cuando importa el efecto secundario: el correo salió, el pago se envió.
Over-mocking — tests que mienten
Ensayar una obra con recortables de cartón en lugar de todos los demás actores — puedes clavar tus frases y aun así no tener ni idea de si el reparto real funcionará junto.
Los falsos son potentes pero peligrosos en exceso. Si haces mock de todo, tu test pasa contra tus suposiciones sobre cómo se comportan las otras partes — no contra cómo se comportan de verdad. El test se pone en verde mientras la integración real está rota. Ese es el antipatrón del over-mocking. Así que haz mock de las dependencias lentas, externas o impredecibles, pero no falsees justo lo que intentas verificar. Un test construido solo con mocks puede pasar mientras el sistema real falla — el verde más peligroso.
- Síntoma
- El test está en verde, pero la misma función falla en producción.
- Causa
Todo lo que la rodea es falso — el test solo comprueba tus suposiciones sobre otras partes.
- Ejemplo
El mock de la base de datos siempre dice «ok», mientras la base de datos real rechaza la consulta por un campo equivocado.
- Remedio
Haz mock solo de lo externo y lento; comprueba las costuras con un Integration Test.
- Relaciones
Mal uso de los Test Doubles; erosiona la confianza igual que un Flaky Test.
Los mocks y los stubs sustituyen a las dependencias reales para que puedas probar en aislamiento. Un stub suministra datos; un mock verifica una llamada. Si abusas del mock, el test pasa mientras la realidad se rompe.
Más allá de los tipos de test está el oficio de escribir buenos — y una disciplina, el desarrollo guiado por tests, que invierte el orden habitual y cambia cómo diseñas el código.
TDD — escribe primero el test
Dibujar la diana antes de disparar, no después — así apuntas a un objetivo definido en lugar de pintar la diana alrededor de donde cayó la flecha.
El desarrollo guiado por tests (TDD, test-driven development) invierte el orden habitual: escribes el test antes que el código. El ciclo es rojo, verde, refactor — escribe un test que falla para lo que quieres (rojo), escribe el código justo para que pase (verde), luego limpia el código con el test vigilándote (refactor). Escribir primero el test te obliga a definir exactamente qué significa el éxito antes de construir, y garantiza que el código sea testeable, porque nació de un test.
- Problema
Los tests se escriben «más tarde» — y el código sale difícil de testear.
- Idea
Primero un test que falla, luego el mínimo código, luego una limpieza. Y vuelta a empezar.
- Ejemplo
El test «carrito vacío → el total es 0» falla; escribes
total(); se pone en verde; ordenas.- Coste
Poco familiar y más lento al principio; difícil cuando la propia tarea aún no está clara.
- Cuándo usarlo
Para lógica con reglas claras: cálculos, validación, corrección de bugs.
- Relaciones
Da código testeable y Living Documentation; el refactor se apoya en Test Behaviour.
Test Behaviour, Not Implementation — comprueba qué, no cómo
Juzgar a un chef por si el plato sabe bien, no por con qué mano sostuvo el cuchillo — te importa el resultado, no los detalles privados de cómo llegó a él.
El hábito más importante para tests duraderos: comprueba qué hace el código, no cómo lo hace — su comportamiento, no su implementación. Prueba que getDiscount devuelve el precio correcto, no que llamó a tres ayudantes internos concretos en orden. Los tests atados al resultado sobreviven al refactor — puedes reescribir las tripas y siguen pasando. Los tests atados a la implementación se rompen cada vez que ordenas el código, lo que enseña a la gente a desconfiar de ellos y a borrarlos. Prueba el comportamiento, y el test sigue siendo útil.
- Problema
Los tests se rompen en cada refactor, aunque el comportamiento no cambió.
- Idea
- Comprueba solo el resultado observable, a través de la interfaz pública.
- Ejemplo
Comprueba que
getDiscountdevolvió 90 — no qué ayudantes llamó por dentro.- Coste
A veces un caso límite es más difícil de alcanzar solo con entrada y salida.
- Cuándo usarlo
- Siempre, por defecto.
- Relaciones
Hace posible el refactor en TDD; los Mocks de más suelen atar los tests a la implementación.
Living Documentation — los tests como documentación
Un conjunto de tests bien escrito se lee como una lista de promesas: «dado esto, hace aquello» — más claro que cualquier comentario sobre cómo debe comportarse el código.
Un conjunto de tests claro hace de documentación viva. Cada test enuncia una promesa — «dado un carrito vacío, el total es cero» — y como los tests se ejecutan, esa documentación nunca puede quedarse anticuada como los comentarios; si cambia el comportamiento, el test se rompe. Así que escribe los tests para que se lean: nombres claros, un comportamiento cada uno, un arrange-act-assert evidente. Un recién llegado debería poder aprender qué hace el código leyendo sus tests. Esa legibilidad vale tanto como la comprobación.
- Problema
Los comentarios y las wikis mienten: el código cambió, el texto se quedó viejo.
- Idea
Los tests son promesas escritas como código. Rompes una promesa — el test se pone en rojo.
- Ejemplo
Un test llamado «carrito vacío — el total es cero». Se lee como una especificación.
- Coste
- Tiempo para nombres claros y un comportamiento por test.
- Cuándo usarlo
- Siempre — sobre todo en código que leen los recién llegados.
- Relaciones
- Se apoya en Arrange–Act–Assert y Test Behaviour.
Escribe primero el test (red-green-refactor), prueba el comportamiento y no la implementación, y hazlo legible — para que los tests sobrevivan a los refactors y sirvan de documentación que no se queda obsoleta.
Un número y una molestia deciden si un conjunto de tests es de verdad fiable. Si lees mal el coverage o toleras la inestabilidad, un conjunto en verde deja de significar nada.
Code Coverage — qué está probado, no lo bien que está
Un mapa que muestra por qué calles pasó una patrulla — útil para ver los barrios nunca visitados, pero pasar delante de una casa no significa que comprobaras las cerraduras.
El code coverage es el porcentaje de tu código que se ejecuta durante los tests. Es una guía útil para encontrar lo que está totalmente sin probar — las calles que nadie patrulló. Pero un coverage alto no significa buenos tests: un test puede ejecutar el código sin afirmar nada significativo, sacando un 100% mientras verifica poco. Usa el coverage para encontrar puntos ciegos, no como prueba de calidad. Que una línea se toque no es lo mismo que que una línea se compruebe.
- Qué es
- La parte de las líneas (o ramas) que se ejecutaron durante los tests.
- Sirve para
- Mostrar puntos ciegos — código que ningún test ejecutó nunca.
- Trampa
No mide la calidad: una línea puede ejecutarse sin que ninguna assertion la compruebe.
- Ejemplo
80% de coverage, pero toda la lógica de descuentos está en el 20% sin cubrir — ahí está el riesgo.
- Cuándo usarlo
- Como linterna para los huecos, no como objetivo.
- Relaciones
Se vuelve una trampa por la Goodhart's Law; no sustituye al Risk-based Testing.
Goodhart's Law — no dejes que el coverage sea el objetivo
Pagar a los obreros por milla de carretera pintada, y verlos pintar líneas largas e inútiles en descampados para llegar al número — la métrica subió, las carreteras no fueron más seguras.
Cuando un número se convierte en objetivo, la gente optimiza el número en lugar de aquello que medía — esa es la ley de Goodhart. Exige «100% de coverage» y obtendrás tests escritos para tocar líneas, no para cazar bugs: tests huecos que no afirman nada, que juegan con la métrica. El coverage es una linterna para encontrar huecos, no un trofeo que maximizar. Persigue la confianza real — ¿los tests cazan de verdad las roturas? — y deja que el coverage sea una pista entre varias, nunca el objetivo en sí.
- Esencia
Cuando una medida se convierte en objetivo, deja de ser una buena medida.
- En testing
Una regla «ningún merge sin 100% de coverage» cría tests sin assertions — solo por el número.
- Ejemplo
Un test llama a la función y no comprueba nada — el coverage sube, la protección es cero.
- Remedio
Pregunta «¿cazaría este test una rotura?» y trata el coverage como una pista.
- Relaciones
- La principal trampa del Code Coverage.
Flaky Test — peor que no tener test
Una alarma de incendios que salta al azar sin motivo: en una semana todos la ignoran por completo, así que cuando hay un incendio de verdad, nadie se mueve.
Un flaky test es uno que pasa y falla al azar sin que el código cambie — normalmente por tiempos, orden o una dependencia oculta. Los flaky tests son veneno: cuando un resultado en rojo puede ser solo ruido, la gente deja de confiar en cualquier rojo, y un fallo real se despacha con un «seguro que es solo flaky». Un test debe ser determinista — mismo código, mismo resultado, siempre. Arregla los flaky tests o bórralos; un conjunto en el que no confías no protege nada.
- Qué es
- Un test que a veces pasa y a veces falla, sin cambios en el código.
- Causas
Tiempos (sleeps, carreras), orden de los tests, una dependencia compartida oculta.
- Ejemplo
Un test espera 100 ms a un servicio; en una máquina de CI ocupada a veces se rinde demasiado pronto.
- Daño
- Enseña al equipo a ignorar el rojo — y un fallo real se cuela.
- Remedio
Haz el test determinista — o bórralo. Nunca convivas con un flaky test.
- Relaciones
Se siente más en casa en E2E; destroza la confianza en el CI Gate.
El coverage muestra qué está probado, no lo bien que está — no lo conviertas en el objetivo. Y un flaky test es peor que ninguno: cuando el rojo puede ser ruido, todo rojo se ignora.
Testear es criterio, no ritual. La habilidad está en probar lo que importa, en las proporciones justas, y en engancharlo a cómo publicas — para que el conjunto gane confianza en lugar de convertirse en trabajo de relleno.
Risk-based Testing — prueba las partes de riesgo, no todo
Compruebas tres veces el paracaídas y los frenos; no le haces una prueba de resistencia al portavasos. El esfuerzo va donde el fallo de verdad duele.
No todo el código merece el mismo testing. El risk-based testing significa concentrar el esfuerzo donde un bug sería costoso o probable: la lógica de negocio central, el dinero, la seguridad, los casos límite delicados, las partes que cambian a menudo. El código trivial y de bajo riesgo puede recibir menos. Perseguir tests para todo malgasta esfuerzo y crea un conjunto tan grande y lento que nadie lo ejecuta. Apunta a tests que cacen los fallos que de verdad lamentarías, no a un número — cubrir lo que importa vale más que cubrirlo todo.
- Problema
El tiempo para testear es escaso, y intentar cubrirlo todo lo reparte demasiado fino.
- Idea
- Más tests donde el fallo es costoso o probable; menos en lo trivial.
- Ejemplo
Las cuentas de pagos y los permisos de acceso — muy probados; los getters y el maquetado simple — lo mínimo.
- Coste
- Tienes que juzgar el riesgo con honestidad, no probar lo que sea fácil.
- Cuándo usarlo
- Cada vez que decides dónde gastar el tiempo de testing.
- Relaciones
Sustituye la persecución del Code Coverage; más denso como Unit Tests sobre la lógica.
CI Gate — tests en cada cambio, automáticamente
Un torniquete que no se abre si tu billete no es válido — la comprobación está integrada en la puerta, no depende de que alguien se acuerde de mirar.
Los tests solo te protegen si de verdad se ejecutan. Engánchalos a tu pipeline para que se ejecuten automáticamente en cada cambio y bloqueen el merge si fallan — el CI gate del curso de deploy. Esto es lo que convierte los tests de algo que quizá ejecutes en una garantía de que nada roto se fusiona. «Tests o no se publica» es el estándar que vale la pena mantener: un cambio sin probar yendo a producción es una apuesta que no tenías por qué hacer.
- Problema
Los tests existen, pero la gente se olvida de ejecutarlos — y el código roto aterriza en main.
- Idea
CI ejecuta todos los tests en cada cambio y rechaza el merge hasta que estén en verde.
- Ejemplo
Un pull request: CI ejecuta los tests, uno falla — el botón de merge queda desactivado.
- Coste
- Esperar a CI; los flaky tests duelen más aquí.
- Cuándo usarlo
- En cualquier proyecto con más de un cambio a la semana.
- Relaciones
Ejecuta toda la Test Pyramid; no puede convivir con los Flaky Tests; caza Regressions antes que los usuarios.
Cómo encaja todo
Una orquesta: cada instrumento importa, pero la música solo sucede juntos.
Los conceptos de este curso funcionan como un solo sistema. La pirámide fija la forma del conjunto de tests, el TDD lo escribe, los test doubles dan aislamiento a los unit tests, y el CI gate lo ejecuta todo en cada cambio — y eso entrega el premio principal: cambiar el código sin miedo. En contra trabajan los flaky tests y el over-mocking, que minan la confianza en el verde. Y el coverage solo insinúa dónde están los huecos.
- ¿Te deja cambiar con confianza — cazaría una regression mañana?
- ¿Tiene forma de pirámide — muchos unit, algunos integration, unos pocos e2e?
- ¿Los tests comprueban el comportamiento, no la implementación interna que se rompe en un refactor?
- ¿Se usan mocks para dependencias externas reales, no para falsear lo que se está probando?
- ¿Es rápido y determinista — sin flaky tests que erosionen la confianza?
- ¿Se ejecuta en CI en cada cambio, bloqueando los merges rotos?
- Cambias el código con confianza, fiándote de que el conjunto cazará lo que rompiste.
- Tus tests forman una pirámide — rápidos en la base, unos pocos realistas arriba.
- Los tests comprueban el comportamiento y sobreviven a los refactors en lugar de romperse con cada limpieza.
- El conjunto es rápido y determinista, y arreglas o borras los tests flaky.
- Los tests se ejecutan en CI en cada cambio, y tratas el coverage como una pista, no como un objetivo.
Chuleta: los 19 conceptos
Por qué testeamos
- Automated Testtest
Código que comprueba código: entrada → llamada → assertion → pasa o falla.
- Regressionregression bug
Un cambio rompe lo que antes funcionaba, a menudo lejos de la edición.
Unit tests
- Unit Testtest de módulo
Una función en aislamiento, en milisegundos. Tienes miles.
- Arrange–Act–AssertAAA
Prepara, haz una cosa, comprueba el resultado.
Integration, e2e y la pirámide
- Integration Testcomprobación de integración
Varias partes reales juntas — comprobando las costuras.
- End-to-End TestE2E
Todo el sistema como lo ve un usuario. Realista, pero lento y frágil.
- Test Pyramidpirámide de testing
Muchos unit, menos integration, unos pocos e2e. No el cono de helado.
Falsos
- Test Doublefalso
Un sustituto de una dependencia lenta, cara o aleatoria.
- Stubrespuesta enlatada
Devuelve una respuesta preparada — alimenta a tu código con datos.
- Mockregistrador de llamadas
Registra llamadas — verifica que ocurrió un efecto secundario.
- Over-mockingdemasiados mocks
Todo con mock — el test está en verde mientras el sistema real falla.
TDD y buenos tests
- TDDred-green-refactor
Primero un test que falla, luego el mínimo código, luego una limpieza.
- Test Behaviour, Not Implementationblack-box testing
Comprueba el resultado por la interfaz pública — el test sobrevive al refactor.
- Living Documentationespecificación ejecutable
Los tests son promesas en código que nunca se quedan obsoletas.
Confiar en el conjunto
- Code Coveragecobertura de tests
Cuánto código se ejecutó en los tests. Una linterna para los huecos, no una medida de calidad.
- Goodhart's Lawmedida vs objetivo
Una medida que se vuelve objetivo deja de medir. 100% de coverage → tests huecos.
- Flaky Testtest inestable
Falla al azar. El remedio: hacerlo determinista, o borrarlo.
Usarlo bien
- Risk-based Testingtesting por riesgo
Más tests donde el fallo es costoso o probable.
- CI Gatecomprobación de merge
Tests en cada cambio; rojo — el merge se bloquea.
Testear bien es criterio: prueba las partes de riesgo, mantén la pirámide, comprueba el comportamiento y no la implementación, y ejecútalo todo automáticamente — para que un conjunto en verde signifique de verdad que es seguro cambiar.