Mejores Prácticas de Pruebas
Reglas que mantienen las suites de pruebas de la API de Node rápidas, fiables y centradas en el comportamiento observable.
Cómo Usar Esta Lista
- Aplícala al añadir la primera prueba a un nuevo servicio.
- Revísala durante las PR que añaden mocks o infraestructura de integración.
- Hazla cumplir a través de CI (se requiere
npm test, trabajo de integración separado).
A - Diseño de Pruebas
- Prueba el comportamiento, no la implementación privada. Afirma el estado HTTP, el JSON devuelto y los efectos secundarios, no el orden de las llamadas internas.
- Sigue la pirámide: muchas unitarias, menos de integración, raras E2E. La mayoría de las pruebas se completan en milisegundos.
- Nombra las pruebas como especificaciones.
devuelve 409 cuando la factura ya está pagadaes mejor quetest1. - Un enfoque de aserción principal por prueba. Múltiples aserciones están bien cuando se verifica un único resultado de comportamiento.
- Casos basados en tablas para variaciones de entrada. Cubre casos extremos sin copiar y pegar pruebas.
B - HTTP y Estructura de la Aplicación
- Exporta
createApp()sin auto-escucha. Supertest y Fastifyinjectnecesitan aplicaciones en proceso. - Cubre rutas de error: manejadores 400, 401, 404, 409, 500. Las suites solo de ruta feliz omiten regresiones.
- Usa Supertest o Fastify inject, no puertos aleatorios. Evita
EADDRINUSEy CI inestable. - No accedas a URLs de producción en las pruebas. Solo staging o en proceso.
- Congela el tiempo al probar la lógica de TTL/caducidad.
vi.setSystemTimeo interfaz de reloj inyectada.
C - Datos y Aislamiento
- Aísla la base de datos por trabajo o suite de CI. Testcontainers o esquema dedicado; nunca una base de datos de desarrollo compartida.
- Trunca o revierte entre pruebas de integración. Evita fallos dependientes del orden.
- Usa fábricas/constructores para entidades de prueba. Configuración legible sin 50 líneas de fixtures en línea.
- Siembra datos mínimos por prueba. Grandes fixtures compartidos ocultan qué campo causó el fallo.
- Ejecuta migraciones contra la base de datos de prueba igual que en producción. Detecta diferencias SQL tempranamente.
D - Herramientas y CI
- Una sola entrada
npm test; divide unitarias vs integración cuando sea necesario.test:integrationpuede requerir Docker. - Prefiere
node:testo Vitest para código nuevo; planifica la salida de Jest en brownfield. Evita tres ejecutores. - Ejecuta pruebas en cada PR después de
typecheckylint. Fallo rápido en el orden de la pipeline. - No fusiones pruebas inestables. Ponlas en cuarentena con un ticket del propietario y una fecha de caducidad, o arréglalas inmediatamente.
- Pruebas de contrato para dependencias HTTP entre servicios. Pact o diff de esquema antes del despliegue.
E - Carga y Lanzamiento
- k6/Artillery smoke en staging antes de lanzamientos importantes. Umbrales de p95 y tasa de error definidos.
- Prueba de carga de rutas de escritura con estrategia de limpieza. Prefijos idempotentes o inquilino dedicado.
- Mide la cobertura; no adores el 100%. Módulos de dominio críticos objetivo; código generado excluido.
- Prueba el middleware de autenticación con tokens realistas. No
auth disabled in testglobalmente a menos que sea una unidad aislada. - Documenta cómo ejecutar pruebas de integración localmente. Prerrequisito de Docker en el README.
Preguntas Frecuentes
¿Por qué el comportamiento sobre la implementación?
Las pruebas de implementación se rompen en la refactorización sin cambio de comportamiento. Las aserciones HTTP/de dominio sobreviven a las reescrituras internas.
¿Qué tan aislada debe estar la base de datos?
Un contenedor por trabajo de CI es ideal. Mínimo: nombre de base de datos separado y truncar entre suites.
¿Cuándo son apropiados los mocks?
APIs externas de terceros e infraestructura lenta en pruebas unitarias. Prefiere Postgres real en integración para la corrección de SQL.
¿Las pruebas E2E deben vivir en el repositorio del servicio?
Viajes críticos sí (smoke de despliegue). Las E2E completas entre productos pueden vivir en un repositorio separado; mantén las pruebas de integración del servicio aquí.
¿Cómo evito las pruebas inestables de Supertest?
Sin singletons mutables compartidos; espera todas las solicitudes; restablece módulos o usa un createApp() nuevo por prueba.
¿`node:test` o Vitest por defecto?
node:test para lógica pura sin dependencias; Vitest cuando el mocking/watch/cobertura dominan el flujo de trabajo.
¿Cuántas pruebas de contrato?
Un pacto por par consumidor-proveedor que cubra los endpoints realmente llamados, no la superficie completa de la API.
¿Prueba de carga en cada PR?
No, nocturna o previa al lanzamiento. Un smoke corto opcional en ramas de lanzamiento.
¿Estrategia de pruebas de NestJS?
Pruebas unitarias de servicios con repositorios mockeados; E2E Supertest para controladores; Testcontainers para integración de DB.
¿Qué pasa con las pruebas de snapshot?
Con moderación para formas estables de errores JSON; prefiere aserciones de campo explícitas para APIs.
Relacionado
- Conceptos Básicos de Pruebas - introducción a la pirámide
- Supertest e Integración HTTP - HTTP en proceso
- Testcontainers - Postgres/Redis reales
Versiones de la pila: Esta página fue escrita para Node.js 24.18.0 (LTS activa), npm 10+, TypeScript 5.6+, Express 5, Fastify 5 y NestJS 11.