Tipos de teste — pirâmide e tradeoffs.
Pirâmide de testes: unitário, integração, end-to-end. Tradeoffs de velocidade, custo de manutenção e fidelidade.
Existem três tipos principais de teste, cada um com um escopo, velocidade e custo de manutenção diferentes. Entender esses tradeoffs é o que permite montar uma suite eficiente — uma que cobre o que importa sem ficar lenta ou frágil.
A pirâmide de testes
A pirâmide de testes é um modelo para distribuir os tipos de teste:
/‾‾‾‾‾‾‾\
/ E2E \ ← poucos, lentos, caros, alta fidelidade
/‾‾‾‾‾‾‾‾‾‾‾\
/ Integração \ ← alguns, velocidade média
/‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾\
/ Unitários \ ← muitos, rápidos, baratos
/‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾\ A proporção recomendada — muitos unitários, alguns de integração, poucos E2E — não é uma regra rígida. É uma consequência dos tradeoffs de cada nível: velocidade, custo de manutenção e fidelidade ao ambiente real do usuário.
Testes unitários — isolados e rápidos
Um teste unitário verifica uma única unidade — uma função ou um componente — em isolamento. Dependências externas (rede, banco de dados, outras funções) são substituídas por mocks quando necessário.
O que testar no blog:
// funções puras — ideal para unitários
calcularTempoLeitura("texto com 400 palavras") === 2
gerarSlug("Introdução ao CSS") === "introducao-ao-css"
formatarData(new Date("2024-01-15")) === "15 de jan. de 2024"
filtrarPorTag(artigos, "css") === [artigosCss]
// componente em isolamento
// ArticleCard renderiza título, autor e tags do artigo passado como prop
// LikeButton mostra ❤️ quando curtido=true e 🤍 quando curtido=false Características: rodam em milissegundos, dão feedback imediato, são fáceis de depurar quando falham — você sabe exatamente qual função ou componente está errado.
Quando não usar unitário: quando o comportamento que você quer verificar só faz sentido com múltiplas peças juntas.
Testes de integração — múltiplas peças juntas
Um teste de integração verifica que duas ou mais peças funcionam corretamente em conjunto. É mais lento que unitário, mas testa comportamentos que unitários não conseguem capturar.
O que testar no blog:
// componente + estado + efeito
// ArticleList com fetch mockado:
// → renderiza loading enquanto o fetch está pendente
// → renderiza os cards quando os dados chegam
// → renderiza mensagem de erro se o fetch falhar
// componente + localStorage
// LikeButton:
// → clicar curte e salva no localStorage
// → remontar o componente carrega o estado salvo
// formulário + validação + callback
// NewsletterForm:
// → botão desabilitado com email inválido
// → submeter com email válido chama onSubmit com o email Características: mais lentos que unitários (precisam renderizar o componente e às vezes simular interações), mas ainda muito mais rápidos que E2E. Dão mais confiança que os unitários porque verificam a integração entre as peças.
Testes E2E — o fluxo real no navegador
Um teste E2E (End-to-End) abre um navegador real e simula o usuário usando a aplicação. Verifica que o sistema inteiro funciona — frontend, requisições de rede, localStorage, DOM — da forma que o usuário experimenta.
O que testar no blog:
// fluxo principal — o caminho que a maioria dos usuários faz
// 1. abrir o blog → ver lista de artigos
// 2. filtrar por tag "css" → ver só artigos de CSS
// 3. clicar em um artigo → ver o artigo completo
// 4. curtir → ver o ícone mudar para ❤️
// 5. recarregar a página → curtida ainda está lá (localStorage)
// fluxo de busca
// 1. digitar "flexbox" no campo de busca
// 2. ver apenas artigos com "flexbox" no título ou descrição O que não testar com E2E:
// ❌ cada caso de formatarData — unitário é suficiente e 100x mais rápido
// ❌ cada estado do LikeButton — integração já cobre
// ❌ cada mensagem de erro de validação — integração já cobre Características: lentos (segundos por teste), podem ser frágeis se usarem seletores instáveis (classes CSS, posição de elementos), e difíceis de depurar quando falham. Use com moderação — nos fluxos críticos que, se quebrarem, travam o uso do produto.
Qual tipo usar para cada caso?
A pergunta prática é: qual o tipo de teste mais barato que ainda me dá a confiança que preciso?
| O que verificar | Tipo ideal |
|---|---|
gerarSlug("Olá, Mundo!") retorna "ola-mundo" | Unitário |
formatarData para 6 entradas diferentes | Unitário com test.each |
ArticleCard renderiza título e autor | Unitário (componente) |
LikeButton salva no localStorage ao clicar | Integração |
ArticleList mostra loading e depois artigos | Integração |
Filtrar artigos na HomePage e ver a lista atualizar | Integração |
| Abrir o blog, ler um artigo, curtir, recarregar | E2E |
A regra prática: vá pelo mais barato que cobre o caso. Se um unitário cobre, não use integração. Se integração cobre, não use E2E.
Resumo
- Unitário: uma função ou componente em isolamento. Rápido, barato, muito deles. Ideal para funções puras e componentes simples.
- Integração: múltiplas peças juntas — componente + estado, componente + API mockada. Velocidade e custo intermediários. Captura o que unitários não conseguem.
- E2E: navegador real, aplicação completa. Lento, frágil, poucos deles. Reservar para fluxos críticos de negócio.
- A pirâmide é uma consequência dos tradeoffs: quanto mais alto o nível, mais lento, mais frágil e mais caro de manter.
- Escolha o tipo mais barato que ainda dá a confiança necessária para o caso específico.
Por que a pirâmide de testes recomenda mais testes unitários e poucos E2E?
O que diferencia um teste de integração de um teste unitário?
Qual é a principal vantagem do teste E2E sobre os demais?
Qual teste seria mais adequado para verificar que 'filtrar artigos por tag retorna apenas artigos com aquela tag'?
Aula concluída
Quase lá.