Contenido del curso

Pruebas a la API de Fake Store

Pruebas en Entornos de Desarrollo Avanzados

Base de datos aislada para pruebas con Docker

Resumen

Aislar la base de datos de pruebas end-to-end de la base de datos de desarrollo es uno de los pasos más importantes al automatizar tests en una API con NestJS y Postgres. Aquí aprenderás a levantar un contenedor Docker independiente, manejar variables de entorno dinámicas y evitar que ambos ambientes colisionen al ejecutarse en paralelo.

¿Por qué necesitas una base de datos separada para pruebas end-to-end?

Mezclar la base de datos de desarrollo con la de pruebas es una receta para el desastre. Tus pruebas necesitan un entorno limpio donde puedas inyectar una semilla de información y borrarla al terminar, sin tocar los datos con los que trabajas día a día.

La solución pasa por levantar un segundo contenedor de Postgres exclusivo para las pruebas. La base de datos de desarrollo conserva su volumen y persistencia, mientras que la de pruebas vive y muere con cada corrida.

¿Para qué sirve aislar la base de datos de pruebas? Para garantizar que los tests corran sobre datos predecibles, sin contaminar tu entorno de desarrollo y sin depender de información que pueda cambiar.

¿Cómo duplicar el contenedor de Postgres en Docker Compose?

La estrategia es copiar la configuración del contenedor original y ajustar tres puntos clave: nombre, credenciales y puerto. En el archivo docker-compose defines un nuevo servicio llamado postgres-end2end con estas variables [02:00]:

  • Nombre de la base de datos: db_end2end.
  • Usuario: end2end.
  • Password: end2end123.
  • Puerto externo: 5433 (el interno sigue siendo 5432).

Un detalle importante: el contenedor de pruebas no necesita un volumen persistente. Como la información se inyecta y elimina en cada corrida, no tiene sentido guardar nada en disco. En cambio, el de desarrollo sí lo conserva.

¿Por qué cambiar solo el puerto externo?

Docker mapea puertos del host al contenedor con la sintaxis externo:interno. Si dejas el puerto interno en 5432 y cambias solo el externo a 5433, ambas bases de datos pueden correr al mismo tiempo sin pisarse [03:50]. Una escucha en localhost:5432 y la otra en localhost:5433.

Para levantar el nuevo contenedor ejecutas docker compose up -d postgres-end2end. Con docker compose ps verificas que ambos servicios están corriendo en paralelo.

¿Cómo cargar variables de entorno dinámicas según el ambiente?

Necesitas un archivo .env.end2end con las credenciales del nuevo contenedor y agregarlo al gitignore para no subir secretos al repositorio [05:30]. Pero el reto está en decidir qué archivo cargar según el ambiente que se ejecute.

La solución es un mapa simple en el archivo de configuración que asocia cada valor de NODE_ENV con su archivo correspondiente:

  • dev carga .env.
  • end2end carga .env.end2end.
  • Cualquier otro valor cae a undefined, lo que significa que las variables se leerán directamente de la máquina host.

Ese último caso es clave para producción y para servidores de integración continua. En plataformas como Heroku, las variables se inyectan en el entorno del servidor, así que no existe un archivo físico que cargar. Heroku incluso setea automáticamente NODE_ENV=production al desplegar.

¿Cómo se construye la lógica condicional en el config?

Guardas el valor de NODE_ENV en una constante. Luego defines un objeto que mapea ambientes a rutas de archivos. Si el ambiente tiene un archivo asociado, asignas options.path con esa ruta y se la pasas al método config() de dotenv. Si no, llamas a config() sin argumentos y deja que las variables se lean del sistema [08:15].

¿Qué hace dotenv cuando no le pasas un path? Carga las variables desde el entorno del sistema operativo donde corre el proceso, sin buscar ningún archivo .env.

¿Cómo conectar las pruebas end-to-end al puerto correcto?

En los scripts de package.json antepones NODE_ENV=end2end al comando que ejecuta las pruebas y al de coverage. La variable se lee en minúsculas, así que respeta esa convención. Por defecto, si no se define nada, el sistema asume dev.

Al correr npm run end2end deberías ver en consola que el config imprime end2end y que la URL de conexión apunta al puerto 5433. Si aparece 5432 ahí, hay un error en tu archivo .env.end2end: revisa que el puerto esté correctamente seteado [13:40].

Una vez corregido el puerto, las pruebas dejan de fallar por errores de conexión. Pero aparece un nuevo síntoma: la base de datos responde, pero está completamente vacía. No tiene tablas ni información.

¿Qué pasa cuando la base de datos de pruebas está vacía?

Al entrar al contenedor con docker compose exec y conectarte como usuario end2end a db_end2end, confirmas que la base existe pero no tiene estructura [16:20]. Ninguna prueba que dependa de datos preexistentes va a pasar, porque ni siquiera hay tablas donde buscar.

Este es el siguiente reto: necesitas correr las migraciones automáticamente al iniciar las pruebas y luego inyectar una semilla con datos predecibles. Solo así tus tests podrán comprobar respuestas reales contra el endpoint.

¿Ya lograste levantar tu contenedor de pruebas en paralelo? Cuéntame en los comentarios qué configuración usas para aislar tus ambientes.