Principios de Pruebas
Referencias Específicas por Lenguaje
Para patrones de pruebas específicos por lenguaje, consulta también:
- TypeScript (Vitest/RTL/Playwright): references/typescript.md
Filosofía Central de Pruebas
- Las pruebas son código de primera clase: Mantén la calidad de las pruebas al mismo nivel que el código de producción.
- Retroalimentación rápida: Las pruebas deben ejecutarse rápidamente y proporcionar retroalimentación inmediata.
- Fiabilidad: Las pruebas deben ser deterministas y reproducibles.
- Independencia: Cada prueba debe ejecutarse de forma aislada.
Proceso TDD [OBLIGATORIO para todos los cambios de código]
Ejecuta este proceso para cada cambio de código:
Fase ROJA
PASO 1: Escribe la prueba que define el comportamiento esperado. PASO 2: Ejecuta la prueba. PASO 3: Confirma que la prueba FALLA (si pasa, la prueba está mal).
Fase VERDE
PASO 1: Escribe el código MÍNIMO para que la prueba pase. PASO 2: Ejecuta la prueba. PASO 3: Confirma que la prueba PASA.
Fase REFACTORIZACIÓN
PASO 1: Mejora la calidad del código (elimina duplicación, mejora nombres). PASO 2: Ejecuta la prueba. PASO 3: Confirma que la prueba SIGUE PASANDO.
Fase VERIFICACIÓN [OBLIGATORIO - SE REQUIEREN 0 ERRORES]
PASO 1: Ejecuta TODOS los comandos de control de calidad para tu lenguaje/proyecto. PASO 2: Corrige cualquier error hasta que TODOS los comandos se ejecuten con 0 errores. PASO 3: Confirma que no hay regresiones.
CUMPLIMIENTO: No se puede avanzar a la siguiente fase si hay fallos en cualquier control de calidad.
Excepciones de TDD (no se requiere TDD)
- Archivos de configuración puros.
- Solo documentación.
- Correcciones de emergencia (pero agrega pruebas inmediatamente después).
- Exploraciones esporádicas (descarta o reescribe con pruebas antes de fusionar).
- Scripts de compilación/despliegue (a menos que contengan lógica de negocio).
Requisitos de Calidad [OBLIGATORIO]
Cobertura
- Trata la cobertura como una señal diagnóstica para encontrar áreas no probadas, no como un objetivo. Los objetivos se manipulan con pruebas triviales.
- Concéntrate en las rutas críticas, la lógica de negocio y el comportamiento cuya regresión importaría.
- Prioriza las aserciones significativas sobre el número de cobertura. Cualquier umbral requerido proviene del CI del proyecto, archivo de tarea, plan de trabajo o Design Doc.
Características de las Pruebas
Todas las pruebas DEBEN ser:
- Independientes: Sin dependencias entre pruebas.
- Reproducibles: La misma entrada siempre produce la misma salida.
- Rápidas: Completar el conjunto completo de pruebas dentro de la ventana de retroalimentación aceptada del proyecto y marcar los conjuntos que ralenticen materialmente la iteración local o el CI.
- Autocomprobables: Aprobado/rechazado claro sin verificación manual.
- Oportunas: Escritas cerca del código que prueban.
CUMPLIMIENTO: Las pruebas que no cumplan CUALQUIER característica DEBEN corregirse inmediatamente.
Tipos de Pruebas
Pruebas Unitarias
Propósito: Probar componentes individuales de forma aislada.
Características:
- Prueban una sola función, método o clase.
- Ejecución rápida (milisegundos).
- Sin dependencias externas.
- Simulan servicios externos.
- Mayoría del conjunto de pruebas.
Pruebas de Integración
Propósito: Probar las interacciones entre componentes.
Características:
- Prueban múltiples componentes juntos.
- Pueden incluir base de datos, sistema de archivos o API.
- Más lentas que las pruebas unitarias.
- Verifican contratos entre módulos.
- Porción más pequeña del conjunto de pruebas.
Pruebas de Extremo a Extremo (E2E)
Propósito: Probar flujos de trabajo completos desde la perspectiva del usuario.
Características:
- Prueban toda la pila de la aplicación.
- Simulan interacciones reales del usuario.
- Tipo de prueba más lento.
- Menor en número.
- Mayor nivel de confianza.
Pirámide de Pruebas
Sigue la estructura de la pirámide de pruebas:
/\ <- Pocas pruebas E2E (Alta confianza, lentas)
/ \
/ \ <- Algunas pruebas de Integración (Confianza media, velocidad media)
/ \
/________\ <- Muchas pruebas Unitarias (Rápidas, fundamentales)
Principios de Diseño de Pruebas
Patrón AAA (Arrange-Act-Assert)
Estructura cada prueba en tres fases claras:
// Arrange: Configurar datos y condiciones de prueba
usuario = crearUsuarioDePrueba()
validador = crearValidador()
// Act: Ejecutar el código bajo prueba
resultado = validador.validar(usuario)
// Assert: Verificar el resultado esperado
assert(resultado.esValido == true)
Una Aserción por Concepto
- Prueba un comportamiento por caso de prueba.
- Múltiples aserciones están bien si prueban un solo concepto.
- Divide las aserciones no relacionadas en pruebas separadas — una prueba DEBE verificar un comportamiento.
Nombres de Prueba Descriptivos
Los nombres de las pruebas deben describir claramente:
- Qué se está probando.
- Bajo qué condiciones.
- Cuál es el resultado esperado.
Formato recomendado: "debería [comportamiento esperado] cuando [condición]"
Independencia de las Pruebas
Requisitos de Aislamiento
- Cada prueba crea sus propios datos de prueba.
- Sin dependencias del orden de ejecución.
- Limpia su propio estado.
- Pasa cuando se ejecuta de forma aislada.
Configuración y Limpieza
- Utiliza hooks de configuración para preparar el entorno de prueba.
- Utiliza hooks de limpieza para liberar recursos.
- Mantén la configuración limitada a los datos, dependencias y fixtures requeridos para el comportamiento bajo prueba.
- Asegúrate de que la limpieza se ejecute incluso si la prueba falla.
Mocking y Dobles de Prueba
Cuándo Usar Mocks
- Mockear dependencias externas: APIs, bases de datos, sistemas de archivos.
- Mockear operaciones lentas: Llamadas de red, cálculos pesados.
- Mockear comportamiento impredecible: Valores aleatorios, hora actual.
- Mockear servicios no disponibles: Servicios de terceros.
Principios de Mocking [OBLIGATORIO]
- Mockear en los límites, no internamente — usa implementaciones reales para utilidades internas.
- Mantén cada mock limitado al comportamiento que la prueba necesita controlar u observar.
- Verifica las expectativas del mock cuando sea relevante.
- Usa adaptadores para bibliotecas/frameworks externos que no controlas.
Tipos de Dobles de Prueba
- Stub: Devuelve valores predeterminados.
- Mock: Verifica que fue llamado correctamente.
- Spy: Registra información sobre las llamadas.
- Fake: Implementación funcional simplificada.
- Dummy: Se pasa pero nunca se usa.
Pruebas de la Capa de Datos
Limitaciones de los Mocks para Acceso a Datos
Los mocks validan patrones de llamada, pero no validan la corrección del esquema, la corrección de las consultas o las restricciones de almacenamiento. Ejemplos de problemas que los mocks pueden pasar por alto:
- desviación de esquema.
- desajustes de columnas o campos.
- joins, filtros o agregaciones incorrectos.
- incompatibilidad de migraciones.
Cuándo la Verificación de la Capa de Datos Real Agrega Valor
Utiliza verificación de acceso a datos real o similar a producción al probar:
- implementaciones de repositorios o DAO.
- mapeos ORM.
- constructores de consultas o SQL sin procesar.
- comportamiento de persistencia que depende de restricciones o forma del esquema.
Opciones de Entorno
Elige la opción más práctica para el entorno del proyecto:
- base de datos contenerizada.
- base de datos de prueba dedicada.
- base de datos en memoria con limitaciones documentadas.
- harness de prueba local basado en adaptadores.
Alineación del Diseño
Cuando un Design Doc incluya Test Boundaries, síguelo como base para decidir qué dependencias se mantienen reales y qué límites se aíslan.
Prácticas de Calidad de Pruebas [OBLIGATORIO]
Mantén las Pruebas Activas
- Corrige o elimina pruebas fallidas: Resuelve los fallos inmediatamente.
- Elimina pruebas comentadas: Corrígelas o elimínalas por completo.
- Mantén las pruebas en ejecución: Las pruebas rotas pierden valor rápidamente.
- Mantén el conjunto de pruebas: Refactoriza las pruebas según sea necesario.
Calidad del Código de Prueba
- Aplica los mismos estándares que al código de producción.
- Utiliza nombres de variables descriptivos.
- Extrae helpers de prueba para reducir la duplicación.
- Mantén las pruebas legibles y mantenibles.
Helpers y Utilidades de Prueba
- Crea constructores de datos de prueba reutilizables.
- Extrae la configuración común en funciones helper.
- Construye utilidades de prueba para escenarios complejos.
- Comparte helpers entre archivos de prueba de manera apropiada.
Qué Probar
Enfócate en el Comportamiento
Prueba el comportamiento observable, no la implementación:
- Bueno: Probar que la función devuelve la salida esperada.
- Bueno: Probar que se llama al endpoint API correcto.
- Malo: Probar que se estableció una variable interna.
- Malo: Probar el orden de las llamadas a métodos privados.
Prueba Casos Límite
Siempre prueba:
- Condiciones límite: Valores mín./máx., colecciones vacías.
- Casos de error: Entrada inválida, valores nulos, datos faltantes.
- Casos extremos: Caracteres especiales, valores extremos.
- Camino feliz: Uso normal y esperado.
Criterios de Calidad de Pruebas [OBLIGATORIO]
- Expectativas literales: Utiliza valores literales hardcodeados en las aserciones — el valor esperado ≠ el valor de retorno del mock (la implementación procesa datos).
- Verificación de resultados: Afirma valores de retorno y estado, no el orden de las llamadas.
- Aserciones significativas: Cada prueba DEBE tener al menos una aserción — una prueba sin aserciones no proporciona valor.
- Mockear solo E/S externa: Mockea DB/API/sistema de archivos, utiliza utilidades internas reales.
- Cobertura de límites: Incluye casos vacío/cero/máximo/error junto con los caminos felices.
CUMPLIMIENTO: Las pruebas que violen CUALQUIER criterio DEBEN reescribirse.
Requisitos de Verificación [OBLIGATORIO para la fase VERIFICACIÓN]
Lista de Verificación Antes de Confirmar
☐ Todas las pruebas pasan. ☐ No hay pruebas omitidas o comentadas. ☐ No queda código de depuración en las pruebas. ☐ El umbral de cobertura se supera cuando el proyecto, archivo de tarea, plan de trabajo o Design Doc lo definen. ☐ Las pruebas se ejecutan en un tiempo razonable.
Política de Tolerancia Cero
- Cero pruebas fallidas: Corregir inmediatamente.
- Cero pruebas omitidas: Eliminar o corregir.
- Cero pruebas inestables: Hacerlas deterministas.
- Cero pruebas lentas: Optimizar o dividir.
CUMPLIMIENTO: No se puede continuar con la finalización de la tarea si FALLA cualquier control de calidad.
Organización de Pruebas
Estructura de Archivos
- Reflejar la estructura de producción: Las pruebas siguen la organización del código.
- Convenciones de nomenclatura claras: Seguir los patrones de archivos de prueba del proyecto.
- Agrupación lógica: Agrupar pruebas relacionadas.
- Separar tipos de pruebas: Unitarias, de integración, E2E en directorios separados.
Organización del Conjunto de Pruebas
tests/
├── unit/ # Pruebas unitarias rápidas y aisladas
├── integration/ # Pruebas de integración
├── e2e/ # Pruebas de extremo a extremo
├── fixtures/ # Datos de prueba y fixtures
└── helpers/ # Utilidades de prueba compartidas
Consideraciones de Rendimiento
Velocidad de las Pruebas
- Pruebas unitarias: < 100ms cada una.
- Pruebas de integración: < 1s cada una.
- Conjunto completo: Debe ejecutarse con frecuencia (< 10 minutos).
Anti-patrones Comunes
Detecta y elimina estos patrones inmediatamente:
- Pruebas que no prueban nada (siempre pasan).
- Pruebas que dependen del orden de ejecución.
- Pruebas que dependen del estado externo.
- Pruebas con lógica compleja (pruebas que necesitan sus propias pruebas).
- Probar detalles de implementación en lugar de comportamiento observable.
- Mocking excesivo (solo mockear límites, usar internos reales).
- Duplicación de código de prueba.
Pruebas Inestables
Elimina las pruebas que fallan de forma intermitente:
- Elimina dependencias de tiempo.
- Usa datos deterministas en lugar de valores aleatorios.
- Asegura una limpieza adecuada.
- Corrige condiciones de carrera.
- Haz que todas las pruebas sean deterministas.
Pruebas de Regresión
- Agrega una prueba por cada corrección de error.
- Mantén un conjunto de pruebas completo.
- Ejecuta el conjunto completo regularmente.
- Elimina una prueba solo cuando el comportamiento cubierto ya no exista o el mismo comportamiento esté cubierto por una prueba más sólida en el nivel correcto.
Código Heredado
- Agrega pruebas de caracterización antes de refactorizar.
- Prueba el comportamiento existente primero.
- Mejora gradualmente la cobertura.
- Refactoriza con confianza.