Desarrollo Guiado por Pruebas
Idioma de salida
Por defecto, se comunica con el usuario en chino simplificado y redacta las estrategias de prueba, las descripciones de pruebas y los resúmenes de implementación en chino simplificado. Cuando el usuario especifique explícitamente otro idioma o la documentación existente tenga otra convención, se respetará esa elección. El código, los comandos, los nombres de productos y las citas que deban conservar su texto original no se traducirán a 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 hacerlo.
Las buenas pruebas son de estilo integración: ejercitan rutas de código reales a través de APIs públicas. Describen qué 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 las refactorizaciones porque no les importa la estructura interna.
Las malas pruebas están acopladas a la implementación. Simulan colaboradores internos, prueban métodos privados o verifican a través de 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 renombras una función interna y las pruebas fallan, esas pruebas estaban probando la implementación, no el comportamiento.
Consulta tests.md para ver ejemplos y mocking.md para conocer las pautas sobre simulaciones.
Antipatrón: Rebanadas horizontales
NO escribas todas las pruebas primero y luego toda la implementación. Esto es "rebanado horizontal" (horizontal slicing): tratar la fase ROJA como "escribir todas las pruebas" y la fase VERDE como "escribir todo el código".
Esto produce pruebas pésimas:
- Las pruebas escritas en masa prueban el 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 los cambios reales: pasan cuando el comportamiento se rompe, fallan cuando el comportamiento es correcto
- Te adelantas a tus propias conclusiones, comprometiéndote con una estructura de prueba antes de entender la implementación
Enfoque correcto: Rebanadas verticales (vertical slices) 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 tocando.
Antes de escribir cualquier código:
- Confirma con el usuario qué cambios de interfaz son necesarios
- Confirma con el usuario qué comportamientos probar (prioriza)
- Identifica 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 otra habilidad automáticamente a menos que el usuario lo solicite explícitamente.
- Enumera los comportamientos a probar (no los pasos de implementación)
- Obtén 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 son más importantes. Enfoca el esfuerzo de prueba en las rutas críticas y la lógica compleja, no en cada posible caso límite.
2. Bala trazadora
Escribe UNA prueba que confirme UNA cosa sobre el sistema:
ROJO: Escribe la prueba para el primer comportamiento → la prueba falla
VERDE: Escribe 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: Escribe 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 centradas en el comportamiento observable
4. Refactorización
Después de que todas las pruebas pasen, busca candidatos a refactorización:
- Extrae duplicación
- Profundiza módulos (mueve la complejidad detrás de interfaces simples)
- Aplica principios SOLID donde sea natural
- Considera lo que el nuevo código revela sobre el código existente
- Ejecuta las pruebas después de cada paso de refactorización
Nunca refactorices mientras estés en ROJO. Llega primero a VERDE.
Lista de verificación por ciclo
[ ] La prueba describe el comportamiento, no la 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 añadieron características especulativas