Desarrollo Guiado por Pruebas (TDD)
Lengua de salida
Por defecto, se comunica en español y escribe las estrategias de prueba, descripciones de pruebas y resúmenes de implementación en español. Cuando el usuario especifique explícitamente otro idioma o la documentación existente tenga otra convención, se respetará esa convención; el código, comandos, nombres de productos y citas que deban conservar el texto original no se traducirán por la fuerza.
Filosofía
Principio fundamental: Las pruebas deben verificar el comportamiento a través de interfaces públicas, no los detalles de implementación. El código puede cambiar por completo; las pruebas no deberían.
Pruebas buenas son de estilo de integración: ejercitan rutas de código reales a través de APIs públicas. Describen lo que hace el sistema, no cómo lo hace. Una buena prueba se lee como una especificación – "el usuario puede finalizar la compra con un carrito válido" te dice exactamente qué capacidad existe. Estas pruebas sobreviven a refactorizaciones porque no les importa la estructura interna.
Pruebas malas están acopladas a la implementación. Simulan colaboradores internos, prueban métodos privados o verifican mediante medios externos (como consultar una base de datos directamente en lugar de usar la interfaz). La señal de alerta: tu prueba se rompe cuando refactorizas, pero el comportamiento no ha cambiado. Si cambias el nombre de una función interna y las pruebas fallan, esas pruebas estaban probando la implementación, no el comportamiento.
Consulta tests.md para ejemplos y mocking.md para pautas sobre mocks.
Anti-patrón: Rebanadas horizontales
NO escribas todas las pruebas primero y luego toda la implementación. Esto es "rebanada horizontal" – tratar ROJO como "escribir todas las pruebas" y VERDE como "escribir todo el código".
Esto produce pruebas basura:
- Las pruebas escritas en masa prueban un comportamiento imaginado, no el real
- Terminas probando la forma de las cosas (estructuras de datos, firmas de funciones) en lugar del comportamiento orientado al usuario
- Las pruebas se vuelven insensibles a cambios reales – pasan cuando el comportamiento se rompe, fallan cuando el comportamiento está bien
- Te adelantas a los hechos, comprometiéndote con una estructura de prueba antes de entender la implementación
Enfoque correcto: Rebanadas verticales mediante balas trazadoras. Una prueba → una implementación → repetir. Cada prueba responde a lo que aprendiste del ciclo anterior. Como acabas de escribir el código, sabes exactamente qué comportamiento importa y cómo verificarlo.
INCORRECTO (horizontal):
ROJO: prueba1, prueba2, prueba3, prueba4, prueba5
VERDE: impl1, impl2, impl3, impl4, impl5
CORRECTO (vertical):
ROJO→VERDE: prueba1→impl1
ROJO→VERDE: prueba2→impl2
ROJO→VERDE: prueba3→impl3
...
Flujo de trabajo
1. Planificación
Al explorar el código base, lee CONTEXT.md (si existe) para que los nombres de las pruebas y el vocabulario de la interfaz coincidan con el lenguaje de dominio del proyecto, y respeta las ADR (Decisiones de Arquitectura Registradas) en el área que estás modificando.
Antes de escribir cualquier código:
- Confirmar con el usuario qué cambios de interfaz son necesarios
- Confirmar con el usuario qué comportamientos probar (priorizar)
- Identificar oportunidades para módulos profundos utilizando principios de diseño de código base cuando los límites de la interfaz no estén claros. No invoques otro skill automáticamente a menos que el usuario lo pida explícitamente.
- Listar los comportamientos a probar (no los pasos de implementación)
- Obtener la aprobación del usuario sobre el plan
Pregunta: "¿Cómo debería ser la interfaz pública? ¿Qué comportamientos son más importantes de probar?"
No puedes probarlo todo. Confirma con el usuario exactamente qué comportamientos importan más. Enfoca el esfuerzo de prueba en rutas críticas y lógica compleja, no en cada posible caso límite.
2. Bala trazadora
Escribe UNA prueba que confirme UNA cosa sobre el sistema:
ROJO: Escribir la prueba para el primer comportamiento → la prueba falla
VERDE: Escribir el código mínimo para que pase → la prueba pasa
Esta es tu bala trazadora – demuestra que la ruta funciona de extremo a extremo.
3. Bucle incremental
Para cada comportamiento restante:
ROJO: Escribir la siguiente prueba → falla
VERDE: Código mínimo para que pase → pasa
Reglas:
- Una prueba a la vez
- Solo el código suficiente para pasar la prueba actual
- No anticipes pruebas futuras
- Mantén las pruebas enfocadas en el comportamiento observable
4. Refactorización
Después de que todas las pruebas pasen, busca candidatos a refactorización:
- Extraer duplicación
- Profundizar módulos (mover la complejidad detrás de interfaces simples)
- Aplicar principios SOLID donde sea natural
- Considerar qué revela el nuevo código sobre el código existente
- Ejecutar pruebas después de cada paso de refactorización
Nunca refactorices estando en ROJO. Llega a VERDE primero.
Lista de verificación por ciclo
[ ] La prueba describe comportamiento, no implementación
[ ] La prueba usa solo la interfaz pública
[ ] La prueba sobreviviría a una refactorización interna
[ ] El código es mínimo para esta prueba
[ ] No se agregaron características especulativas