Escribimos el test primero. Vemos cómo falla. Escribimos el código mínimo para que pase. Refactorizamos. Repetimos.
TDD invierte el orden natural del desarrollo: en lugar de escribir código y luego verificar que funciona, primero escribimos una prueba automática que describe el comportamiento esperado, vemos cómo falla, y solo entonces escribimos el código más simple que la hace pasar.
El resultado es código que nació testeado: cada línea de producción tiene una prueba que la justifica, la documenta y la protege de regresiones futuras.
No es una técnica para atrapar bugs después. Es una forma de diseñar software empujado por el comportamiento que necesitamos, no por la implementación que ya escribimos.
Tres pasos cortos que se repiten miles de veces. Cada uno tiene un propósito claro.
Escribir un test que describe el siguiente comportamiento deseado. Antes de ejecutarlo, sé que va a fallar — la feature todavía no existe.
El test falla por la razón correcta: "feature no implementada", no por errores de configuración o setup.
Hacerlo pasar con el código más simple posible. Sin optimizaciones, sin generalizaciones prematuras, sin arquitectura futura.
"Fake it 'til you make it" es válido mientras el test guíe. La abstracción viene después.
Con la red de tests protegiéndote, limpiar el código: eliminar duplicación, mejorar nombres, extraer abstracciones que el patrón reveló.
Los tests siguen verdes durante todo el refactor — confianza para cambiar sin miedo.
Un ejemplo real: agregar validación de RUT chileno a un formulario. Así se ve TDD en el historial de Git.
test: validar formato de RUT debe aceptar 12.345.678-9
// Primero el test — describe el comportamiento esperado
expect(validarRut('12.345.678-9')).toBe(true);
expect(validarRut('123456789')).toBe(false);
✗ 1 failed · validarRut is not defined
feat: validar RUT chileno con dígito verificador
// El código mínimo para que el test pase
function validarRut(rut) {
const [num, dv] = rut.replace(/\./g, '').split('-');
// cálculo simple del dígito verificador
return calcularDV(num) === dv.toLowerCase();
}
✓ 2 passed
refactor: extraer cálculo de DV + agregar tests de borde
// Limpiar con la red de tests como red de seguridad
expect(validarRut('1-9')).toBe(true); // mínimo
expect(validarRut('k')).toBe(false); // DV no numérico
expect(validarRut('')).toBe(false); // vacío
✓ 5 passed
Cambiás código con confianza: si rompiste algo, un test lo dice en segundos, no un cliente en producción.
Escribir el test primero fuerza interfaces claras. La API se vuelve obvia porque el primer consumidor es el test.
El test es la documentación: muestra exactamente qué hace el código, con ejemplos ejecutables que no se desactualizan.
Cada cambio se valida en milisegundos. La fricción de "escribir test → correr → ver rojo" es lo que evita arrastrar bugs.
Las primeras semanas son más lentas. A los 3-6 meses, refactors grandes que antes tomaban semanas se hacen en horas.
Lo que no se prueba, eventualmente falla. Lo que se prueba desde el commit nº 1 se rompe en CI, no en el cliente.
Conversemos 30 minutos sobre cómo encarar tu próximo desafío con un equipo que ya trabaja así.
Reservar una reunión