Testes de Integração TypeScript com Docker: Nível Avançado
\n\nTestes de integração são uma etapa fundamental para verificar a interação entre os componentes do sistema. Para aplicações TypeScript, especialmente com arquitetura de microsserviços, o Docker se torna uma ferramenta indispensável. Neste artigo, exploraremos técnicas avançadas de configuração e execução de testes de integração usando Docker, que ajudarão a aumentar a confiabilidade e a velocidade do desenvolvimento.
\n\n1. Por que usar Docker para testes de integração TypeScript?
\nO Docker permite isolar os ambientes de teste, garantindo sua reprodutibilidade. Em vez de configurar manualmente bancos de dados, filas de mensagens e outras dependências, você as executa em contêineres. Isso é especialmente importante para projetos TypeScript, onde a tipagem pode ocultar erros de tempo de execução que surgem justamente durante a integração.
\n- \n
- Isolamento: cada teste é executado em um ambiente limpo \n
- Velocidade: contêineres são iniciados em segundos \n
- Paralelismo: é possível testar diferentes versões de dependências simultaneamente \n
2. Configuração do Docker Compose para o ambiente de teste
\nVamos criar um docker-compose.test.yml que sobe PostgreSQL, Redis e a própria aplicação para testes:
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"]\nAqui usamos tmpfs para o banco de dados, para que os dados não sejam salvos entre as execuções, acelerando os testes.
3. Configuração avançada de testes TypeScript com TestContainers
\nA biblioteca testcontainers permite gerenciar contêineres diretamente do código TypeScript. Isso oferece flexibilidade: você pode iniciar contêineres apenas para cenários de teste específicos.
Instalação:
\nnpm install --save-dev testcontainers\nExemplo de teste de integração com contêiner 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 // Inicia o contêiner 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 // Conecta ao banco de dados de teste\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 // Executa as migrações\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 cria um usuário no banco de dados', 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