Testes de Integração no Node.js verificam se componentes reais funcionam juntos: aplicação, banco de dados, cache, fila, sistema de arquivos ou servidor HTTP. Eles detectam problemas que mocks não conseguem revelar, como queries inválidas, serialização incorreta e configuração incompatível.
Esses testes são mais lentos que testes unitários, mas oferecem confiança nas fronteiras críticas. O segredo é isolar dados, controlar recursos e manter a execução reproduzível.
Neste guia, você aprenderá estrutura, banco real, servidor em porta aleatória, limpeza, transações, containers, CI e boas práticas.
O que testar
- rotas HTTP completas;
- queries e migrações;
- serialização de mensagens;
- cache e expiração;
- uploads e arquivos;
- integração entre módulos internos.
Aplicação separada do servidor
Não abra a porta durante o import. Exporte uma fábrica:
export function criarApp({ repository, logger }) {
return createServer(async (req, res) => {
// rotas
});
}O processo de produção chama listen(), enquanto o teste controla o ciclo de vida.
Porta aleatória
const server = criarApp(deps);
server.listen(0);
await once(server, 'listening');
const address = server.address();
const baseUrl = `http://127.0.0.1:${address.port}`;A porta zero evita conflito com outras suítes.
Encerramento
after(async () => {
await new Promise((resolve, reject) => {
server.close((error) => error ? reject(error) : resolve());
});
});Feche servidores, pools, workers e timers mesmo quando um teste falha.
Banco de dados real
Use a mesma tecnologia de produção quando o comportamento do driver importa. Bancos em memória podem ocultar diferenças de tipos, constraints e transações.
Migrações
A suíte deve aplicar migrações em banco vazio. Isso testa se uma nova instalação pode chegar ao schema esperado.
Isolamento de dados
Estratégias comuns:
- transação revertida após o teste;
- schema por worker;
- banco por suíte;
- limpeza por tabelas;
- IDs únicos por caso.
Escolha uma estratégia compatível com paralelismo.
Fixtures
Mantenha fixtures pequenas e explícitas. Evite um dump gigante compartilhado por toda a suíte.
async function criarUsuario(overrides = {}) {
return repository.salvar({
id: randomUUID(),
email: 'teste@example.com',
active: true,
...overrides
});
}HTTP real
const response = await fetch(`${baseUrl}/users`, {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ email: 'a@b.com' })
});
assert.equal(response.status, 201);Verifique status, headers, corpo e efeitos persistidos.
Autenticação
Crie tokens ou sessões por helper de teste usando as mesmas regras da aplicação. Não desative autorização globalmente.
Serviços externos
Evite chamar APIs públicas durante CI. Use sandbox oficial, servidor fake com protocolo real ou container local. O teste precisa validar sua integração sem depender da disponibilidade da internet.
Filas
Teste publicação, consumo, ack, retry e idempotência. Aguarde sinais explícitos em vez de usar sleeps longos.
Cache
Verifique hit, miss, TTL, invalidação e isolamento de chaves. Limpe o namespace após a suíte.
Containers
Containers ajudam a iniciar versões controladas de banco, Redis e broker. Fixe imagens e aguarde health checks antes de executar testes.
CI
npm ci
npm run db:migrate:test
node --test test/integrationO pipeline deve capturar logs dos serviços quando houver falha.
Paralelismo
Testes paralelos precisam de recursos isolados. Portas fixas, tabelas compartilhadas e filas com o mesmo nome causam flakiness.
Timeouts
Defina timeouts realistas e diagnostique lentidão. Aumentar o limite continuamente esconde deadlocks e recursos não encerrados.
Mocks versus integração
Use mocks para regras locais e integração real para fronteiras. Consulte Mocking no Node.js.
Test runner
Hooks, subtests e timeouts podem ser organizados com Node Test Runner no Node.js.
Erros comuns
- usar banco diferente da produção;
- não aplicar migrações;
- compartilhar dados;
- depender de ordem;
- usar sleep para sincronizar;
- chamar internet externa;
- não fechar recursos;
- ocultar logs de falha.
Checklist
- ambiente isolado;
- migrações aplicadas;
- dados determinísticos;
- porta aleatória;
- recursos encerrados;
- serviços com versão fixa;
- timeouts;
- logs disponíveis;
- execução reproduzível no CI.
Conclusão
Testes de Integração no Node.js validam as conexões que sustentam a aplicação. Eles comprovam que contratos internos, drivers e infraestrutura funcionam juntos.
Mantenha o ambiente controlado, os dados isolados e o ciclo de vida explícito. Uma suíte menor e confiável oferece mais valor que centenas de testes instáveis.
Consulte a documentação oficial do node:test e a documentação HTTP do Node.js.


