Testes unitários integração e e2e resolvem perguntas diferentes. O teste unitário isola um componente e roda em milissegundos; o de integração junta peças e depende de banco ou mensageria; o E2E percorre a cadeia inteira e é o mais lento dos três. A escolha depende do que você precisa garantir naquele momento.
Testes unitários, integração e E2E: qual é a diferença real?
Testes unitários integração e e2e se diferenciam pelo escopo e pelo custo de execução, não pelo nome da ferramenta usada. O teste unitário isola um componente e valida uma regra; o teste de integração verifica a junção de peças; o E2E percorre a cadeia completa, da entrada HTTP até a resposta final.
A definição importa porque a mesma função de teste pode pertencer a categorias diferentes dependendo de quantas dependências reais ela toca. Quando você troca o banco real por um dublê, o teste deixa de ser integração e passa a ser unitário. Quando você sobe o servidor numa porta e dispara requisições, deixa de ser integração e vira E2E.
Wesley Willians, instrutor da Full Cycle, apresentou essa distinção em um vídeo publicado em 9 de janeiro de 2025 no canal Full Cycle. O argumento central é que a confusão entre os três tipos é comum até entre profissionais experientes, porque a fronteira depende de decisões de escopo que o próprio time toma.
A tabela abaixo resume as três categorias nas dimensões que costumam decidir a escolha.
O que caracteriza um teste de unidade
Um teste de unidade valida o comportamento de um componente isolado, substituindo as dependências externas por dublês para que o resultado não dependa de nada além do código sob teste. Se outra classe pode alterar o resultado, o teste não é unitário.
Esse isolamento tem uma consequência prática: o teste roda em milissegundos e pode ser executado milhares de vezes durante o desenvolvimento. A velocidade permite manter uma cobertura alta sobre regras de negócio sem transformar a esteira de integração contínua em um gargalo.
Escrever testes unitários também expõe o nível de acoplamento do código. Quando uma classe depende de forma explícita de muitos componentes externos, montar o teste exige uma quantidade grande de dublês. O esforço para testar sinaliza o esforço para dar manutenção naquele trecho.
Dublês de teste, como mocks e stubs, simulam o comportamento esperado das dependências. Eles resolvem o problema imediato do isolamento, mas não provam que a integração real funciona. Essa prova pertence à categoria seguinte.
Quando o teste de integração passa a valer a pena
O teste de integração verifica se componentes que funcionam separadamente continuam funcionando quando são combinados. Peças corretas isoladamente podem falhar na junção: contratos divergentes, formatos de data incompatíveis ou transações mal delimitadas só aparecem nesse nível.
O grau de realismo é uma decisão explícita do time. Uma opção é usar banco em memória ou uma classe que simula persistência; outra é executar contra uma instância real do banco. As duas abordagens contam como integração, mas entregam garantias diferentes.
Quando o teste toca um banco real, cada execução precisa limpar o estado antes ou depois. Sem essa limpeza, um teste pode influenciar o resultado do seguinte, e a suíte passa a falhar de forma intermitente conforme a ordem de execução muda.
Ferramentas como Testcontainers sobem dependências descartáveis, como bancos de dados e sistemas de mensageria, em contêineres durante a execução da suíte. O custo em tempo de execução sobe, mas o ambiente fica próximo do real sem exigir infraestrutura permanente.
O que um teste end-to-end cobre de verdade
Um teste end-to-end percorre a aplicação como um usuário ou cliente externo faria. A interpretação do que é ponta a ponta varia: pode significar subir o servidor em uma porta e disparar requisições HTTP, ou cobrir apenas uma rota específica dentro de um microsserviço.
O escopo amplo tem um preço. Quanto mais camadas o teste atravessa, mais lento ele fica e mais pontos de falha acumula. Proxy reverso, balanceador, dependências entre microsserviços e serviços de terceiros entram na conta quando o teste não delimita onde começa e onde termina.
Em alguns casos, a cadeia inteira é necessária. Em outros, é aceitável testar de uma rota para baixo, exercitando o roteador e o restante do fluxo sem subir o servidor em uma porta. Ferramentas que atuam como cliente HTTP em tempo de execução, como o Supertest, permitem esse recorte.
A decisão de escopo pertence ao time. O erro comum é tratar toda cadeia como obrigatória por padrão, o que transforma a suíte E2E no conjunto mais lento e mais frágil do projeto.
Comparação entre teste unitário, integração e E2E
Cada categoria troca velocidade por abrangência. A tabela abaixo resume a troca nas dimensões que costumam orientar a decisão de qual teste escrever primeiro.
| Critério | Teste unitário | Teste de integração | Teste E2E |
|---|---|---|---|
| Escopo | Um componente isolado | Junção de componentes | Cadeia completa |
| Uso de dublês | Alto, dependências simuladas | Parcial ou nenhum | Nenhum |
| Velocidade | Milissegundos por teste | Segundos, sobe dependências | Os mais lentos da suíte |
| Custo de manutenção | Baixo | Médio | Alto |
| Principal risco coberto | Regra de negócio isolada | Contrato entre peças | Fluxo real de ponta a ponta |
A pirâmide de testes reflete essa troca: muitas unidades, menos integração e poucos testes E2E. A proporção não é uma regra fixa, mas a lógica de custo crescente se mantém na maioria dos projetos.
Como decidir o escopo de cada teste
Antes de escrever o teste, defina onde ele começa e onde termina. Essa decisão determina a categoria, a ferramenta e o custo de manutenção. O mesmo componente pode ser validado por um teste unitário em um momento e por um teste de integração em outro, dependendo do que precisa ser garantido.
- Pergunte qual garantia falta na suíte atual. Se regras de negócio isoladas não estão cobertas, comece por testes unitários.
2. Se a falha acontece na junção entre componentes ou no acesso ao banco, escreva um teste de integração com a dependência real ou um substituto próximo dela.
3. Reserve o E2E para fluxos que representam risco de negócio e que só fazem sentido de ponta a ponta.
4. Ajuste o realismo da dependência ao risco: banco em memória para contratos simples, contêiner descartável quando o comportamento do banco importa.
5. Revise a proporção da suíte periodicamente. Uma suíte dominada por testes E2E costuma indicar cobertura insuficiente nos níveis mais baratos.
Boas práticas que atravessam os três tipos
A prática vale para qualquer um dos três níveis: cada teste precisa deixar o ambiente no estado em que o encontrou. Limpar o banco, encerrar contêineres e remover arquivos temporários evita que a ordem de execução mude o resultado.
Teste automatizado é investimento de longo prazo. Um teste escrito há três anos continua rodando na suíte e sinalizando regressões, desde que a equipe mantenha o teste junto com o código que ele cobre.
O canal Full Cycle publica conteúdo sobre testes automatizados, TDD e desenvolvimento de software, e o vídeo de 9 de janeiro de 2025 discutiu essas três categorias em quatorze minutos. O material é útil como ponto de partida para times que estão definindo a estratégia de testes.
Para quem quer um caminho estruturado, o Bootcamp do Dev Doido e o Crazystack Typescript cobrem fundamentos de desenvolvimento com foco em prática. Gustavo Dev Doido mantém esse material voltado a quem está começando ou consolidando a base técnica.
Perguntas frequentes sobre testes unitários, integração e E2E
- Teste unitário pode usar banco de dados real? Não, isso o descaracteriza. Se o teste toca um banco real, ele passa a ser um teste de integração, porque o resultado depende de um componente externo ao código sob teste.
- Qual a diferença entre mock e stub? Ambos são dublês de teste. O stub devolve respostas predefinidas quando chamado; o mock também registra e verifica como a dependência foi usada durante o teste.
- Teste de integração precisa de banco real? Não necessariamente. Banco em memória ou uma classe que simula persistência contam como integração, mas oferecem garantias menores do que uma instância real do banco.
- Quando um teste E2E vale o custo? Quando o fluxo representa risco de negócio e depende de várias camadas funcionando juntas, como um processo de checkout ou uma jornada de cadastro completa.
- O que é Testcontainers? É uma biblioteca que sobe dependências descartáveis em contêineres, como bancos de dados e sistemas de mensageria, durante a execução da suíte de testes.
- Por que a pirâmide de testes tem mais testes unitários? Porque o custo cresce do unitário para o E2E. Testes unitários rodam em milissegundos e cobrem regras isoladas, enquanto os E2E são lentos e caros de manter.
- Teste de integração pode substituir o teste unitário? Não. Eles cobrem riscos diferentes: o unitário valida regras isoladas com rapidez, e o de integração valida contratos entre componentes.
- Preciso limpar o banco entre testes de integração? Sim. Sem limpeza, um teste pode alterar o estado que o próximo espera, o que gera falhas intermitentes conforme a ordem de execução muda.
- Como saber se meu teste é unitário ou de integração? Verifique quantas dependências reais ele toca. Se todas as dependências externas são dublês, o teste é unitário; se alguma é real, ele é de integração.