Pruebas de Integración de TypeScript con Docker: Nivel Avanzado
\n\nLas pruebas de integración son una etapa clave para verificar la interacción entre los componentes del sistema. Para aplicaciones TypeScript, especialmente con arquitectura de microservicios, Docker se convierte en una herramienta indispensable. En este artículo, exploraremos técnicas avanzadas para configurar y ejecutar pruebas de integración usando Docker, que te ayudarán a aumentar la confiabilidad y la velocidad de desarrollo.
\n\n1. ¿Por qué Docker para pruebas de integración de TypeScript?
\nDocker permite aislar los entornos de prueba, garantizando su reproducibilidad. En lugar de configurar manualmente bases de datos, colas de mensajes y otras dependencias, las ejecutas en contenedores. Esto es especialmente importante para proyectos TypeScript, donde la tipificación puede ocultar errores en tiempo de ejecución que surgen precisamente durante la integración.
\n- \n
- Aislamiento: cada prueba se ejecuta en un entorno limpio \n
- Velocidad: los contenedores se inician en segundos \n
- Paralelismo: se pueden probar simultáneamente diferentes versiones de dependencias \n
2. Configuración de Docker Compose para el entorno de pruebas
\nCrearemos un docker-compose.test.yml que levante PostgreSQL, Redis y la propia aplicación para las pruebas:
version: '3.8'\nservices:\n db-test:\n image: postgres:15-alpine\n environment:\n POSTGRES_DB: testdb\n POSTGRES_USER: test\n POSTGRES_PASSWORD: testpass\n ports:\n - "5433:5432"\n tmpfs: /var/lib/postgresql/data\n\n redis-test:\n image: redis:7-alpine\n ports:\n - "6380:6379"\n\n app-test:\n build:\n context: .\n dockerfile: Dockerfile.test\n environment:\n DATABASE_URL: postgres://test:testpass@db-test:5432/testdb\n REDIS_URL: redis://redis-test:6379\n depends_on:\n - db-test\n - redis-test\n command: ["npm", "run", "test:integration"]\nAquí usamos tmpfs para la base de datos, para que los datos no se guarden entre ejecuciones, lo que acelera las pruebas.
3. Configuración avanzada de pruebas TypeScript con TestContainers
\nLa librería testcontainers permite gestionar contenedores directamente desde el código TypeScript. Esto brinda flexibilidad: puedes levantar contenedores solo para ciertos escenarios de prueba.
Instalación:
\nnpm install --save-dev testcontainers\nEjemplo de una prueba de integración con un contenedor dinámico:
\nimport { GenericContainer, StartedTestContainer } from 'testcontainers';\nimport { Client } from 'pg';\nimport { UserService } from './user-service';\n\nlet container: StartedTestContainer;\nlet client: Client;\n\nbeforeAll(async () => {\n // Iniciamos el contenedor de PostgreSQL\n container = await new GenericContainer('postgres:15-alpine')\n .withEnvironment({\n POSTGRES_DB: 'test',\n POSTGRES_USER: 'test',\n POSTGRES_PASSWORD: 'test'\n })\n .withExposedPorts(5432)\n .start();\n\n // Nos conectamos a la BD de prueba\n const host = container.getHost();\n const port = container.getMappedPort(5432);\n client = new Client({\n host,\n port,\n database: 'test',\n user: 'test',\n password: 'test'\n });\n await client.connect();\n\n // Ejecutamos las migraciones\n await client.query(`\n CREATE TABLE users (\n id SERIAL PRIMARY KEY,\n email VARCHAR(255) UNIQUE NOT NULL,\n name VARCHAR(255)\n )\n `);\n});\n\nafterAll(async () => {\n await client.end();\n await container.stop();\n});\n\ntest('UserService.createUser crea un usuario en la BD', async () => {\n const userService = new UserService(client);\n const user = await userService.createUser({\n email: 'test@example.com',\n name: 'Test User'\n });\n\n const result = await client.query('SELECT * FROM users WHERE email = $1', ['test@example.com']);\n expect(result.rows[0]).toMatchObject({\n email: 'test@example.com',\n