A Pirâmide de Teste
A pirâmide é o jeito mais comum de organizar os nívei de teste: cada camada enfatiza o volume de testes em relação à camada de cima. A base concentra muito mais testes do que o topo.
Uma nuance prática da pirâmide: os níveis da base (Unidade e Integração) costumam ser automatizados via API/código; os níveis do topo (Sistema e Aceite) costumam ser automatizados via GUI (interface gráfica) — e testes via GUI são estruturalmente mais lentos e mais frágeis que testes via API, o que é mais um motivo para concentrar volume na base.
O conceito por trás da pirâmide é simples: garantia da qualidade e teste antecipado em ação (o shift-left). Cada nível exige um ambiente de teste adequado, idealmente reproduzindo a produção cada vez mais fielmente à medida que se sobe na pirâmide.
A intuição por trás de cada nível
Antes da tabela detalhada, vale fixar o que cada nível realmente pergunta:
- Unidade — essa função/classe isolada faz o que deveria fazer?
- Integração — A e B conversam direito entre si (formato de dado certo, ordem de chamada certa, timeout tratado)?
- Sistema — o sistema inteiro, de ponta a ponta, isolado do resto do mundo, se comporta como esperado?
- Aceite — a pergunta muda de natureza: não é mais "tem defeito?", é "isso resolve o problema de negócio?". Se um defeito aparece aqui, algo já deveria ter sido pego antes.
Os quatro níveis, lado a lado
| Nível | Objetivo | Base de teste | Objetos de teste | Falhas/defeitos típicos | Responsabilidade |
|---|---|---|---|---|---|
| Unidade (Componente) | Reduzir riscos, verificar comportamento de componentes, criar confiança, encontrar defeitos | Design detalhado, código, modelo de dados, especificações de componente | Componentes, unidades/módulos, estruturas de código e dados, classes | Funcionalidade incorreta, problemas de fluxo de dados, código/lógica incorretos | Geralmente o próprio desenvolvedor que escreveu o código |
| Integração | Reduzir riscos, verificar comportamentos de interface, criar confiança, encontrar defeitos | Projeto de software/sistema, diagramas de sequência, especificações de interface, arquitetura | Subsistemas, bancos de dados, infraestrutura, interfaces, APIs, microsserviços | Dados incorretos/ausentes, sequenciamento/sincronização incorretos, incompatibilidade de interface, falhas de conformidade regulamentar | Desenvolvedores (integração de componentes) e/ou testadores (integração de sistema) |
| Sistema | Verificar e validar comportamento de ponta a ponta, qualidade dos dados, atender requisitos regulamentares | Requisitos funcionais/não funcionais, análise de risco, casos de uso, histórias | Aplicativos, sistemas completos, configuração do sistema | Comportamento funcional/não funcional incorreto, falhas de ponta a ponta, problemas de ambiente | Testadores independentes |
| Aceite | Estabelecer confiança, avaliar prontidão para implantação, satisfazer requisitos legais/contratuais — normalmente não busca encontrar defeitos | Processos de negócio, requisitos do usuário, regulamentos, contratos, documentação | Sistema em teste, dados de configuração, processos de negócio, sistemas de recuperação | Fluxos de trabalho que não atendem requisitos de negócio, regras de negócio mal implementadas, violação de requisitos contratuais | Usuários de negócio, operações, ou auditores (conforme o tipo) |
Integração tem mais de um nível
Na prática, "teste de integração" quase nunca é um nível único — um projeto costuma ter pelo menos dois:
- Integração de componentes: testa a interação entre unidades/componentes. Segue o teste de unidade, geralmente automatizado, e costuma ser feito por quem desenvolveu o código.
- Integração de sistema: testa a interação entre sistemas, pacotes e microsserviços. Pode se sobrepor ou seguir o teste de sistema, e é bem mais complexo — múltiplas organizações controlando interfaces diferentes torna qualquer mudança mais arriscada, processos de negócio podem abranger vários sistemas, e problemas de compatibilidade de hardware/sistema podem surgir.
Risco adicional da integração de sistema: você geralmente não controla a outra ponta — um sistema externo (como o ambiente da Receita Federal para e-Financeira) pode mudar contrato, formato ou disponibilidade sem aviso, e isso fica fora do seu controle de versionamento.
Por isso, planejar a estratégia de integração (em que ordem os componentes/sistemas são combinados) antes de construí-los tende a maximizar a eficiência do teste — integrar e testar em pequenos incrementos facilita isolar onde um defeito entrou.
Por que essa ordem importa
O objetivo geral de cada nível anterior é evitar que defeitos escapem para o nível seguinte — ou pior, para produção. Um defeito pego no teste de unidade nunca chega a custar o que custaria se fosse pego só no teste de aceite.
Pense em cada nível como uma barreira sequencial: o trabalho dele é não deixar o defeito passar para a próxima camada. É a mesma curva de custo do Módulo 1, só que aplicada à pirâmide — um defeito pego na Unidade custa cerca de 1x; o mesmo defeito, pego só na Aceite (ou pior, em produção), pode custar perto de 100x.
Este módulo ficou só na famíliarização com os níveis — como escrever, automatizar e organizar testes em cada um deles na prática (com código C#/xUnit do projeto) vem em módulos específicos mais adiante.
Tipos de Teste (ortogonais aos níveis)
Até agora vimos onde testamos (os quatro níveis da pirâmide). Agora entra o quê e como testamos — os tipos de teste. A diferença crucial: tipo de teste não é mais um nível, é um eixo ortogonal. Você aplica qualquer tipo de teste dentro de qualquer nível, um teste de Unidade pode ser funcional ou não funcional, caixa-branca ou caixa-preta, e o mesmo vale para Integração, Sistema e Aceite.
Estático x Dinâmico
Teste estático avalia o artefato sem executar o código: análise estática (ferramentas que inspecionam o código em busca de padrões problemáticos) e revisão (leitura humana — code review, walkthrough, inspeção formal). Teste dinâmico exige executar o código ou sistema — é o que normalmente vem à mente quando se fala em "teste".
Dentro do teste dinâmico, existem três abordagens de design de caso de teste:
- Caixa-branca (estrutural) — deriva casos de teste a partir da estrutura interna/implementação. Mede cobertura estrutural (ex.: % do código de um componente exercitado, % de interfaces testadas numa integração).
- Caixa-preta (comportamental) — deriva casos de teste a partir de especificação/comportamento esperado, sem olhar para o código por dentro. Se divide em funcional (testa o quê o sistema faz) e não funcional (testa quão bem o sistema faz o que faz — desempenho, usabilidade, confiabilidade, segurança, portabilidade).
- Baseado em experiência — usa o conhecimento e a intuição de quem testa (bugs comuns, histórico do sistema, heurísticas), em vez de uma técnica formal derivada de especificação ou de código.
Uma distinção à parte, que às vezes se confunde com essas três: design de teste (decidir quais casos escrever) e execução de teste (rodar esses casos) são duas atividades diferentes do processo, não um tipo de teste — qualquer um dos três tipos acima passa por ambas.]
Funcional x Não funcional, nível por nível
O mesmo nível da pirâmide pode receber os dois tipos, testando coisas completamente diferentes:
| Nível | Exemplo funcional ("o quê") | Exemplo não funcional ("quão bem") |
|---|---|---|
| Componente | Calcula os juros compostos corretamente | Desempenho: ciclos de CPU para um cálculo de juros complexo |
| Integração de componentes | Repassa os dados da conta capturados na interface para a lógica de negócio | Segurança: vulnerabilidade de estouro de buffer nos dados que trafegam da UI para a lógica |
| Sistema | Correntista consegue solicitar uma linha de crédito na conta | Portabilidade: a camada de apresentação funciona em todos os navegadores/dispositivos suportados |
| Integração de sistema | Sistema consulta um microsserviço externo de pontuação de crédito | Confiabilidade: robustez se o microsserviço de pontuação não responder |
| Aceite | Banqueiro aprova ou recusa um pedido de crédito | Usabilidade: acessibilidade da interface de crédito para pessoas com deficiência |
Caixa-branca, nível por nível
| Nível | Exemplo de teste caixa-branca |
|---|---|
| Componente | Cobertura de declaração e de decisão para os componentes que fazem cálculos financeiros |
| Integração de componentes | Exercitar como cada tela repassa dados para a próxima tela e para a lógica de negócio |
| Sistema | Cobrir as sequências de páginas possíveis num fluxo de solicitação de crédito |
| Integração de sistema | Exercitar todos os tipos de consulta enviados ao microsserviço de pontuação |
| Aceite | Cobrir todas as estruturas de arquivo de dados financeiros suportadas e as faixas de valores de transferência |
Teste relacionado à mudança: confirmação e regressão
Esse é o quinto tipo, e também se aplica a todos os níveis:
- Teste de confirmação — verifica se um defeito específico, já identificado, foi de fato corrigido.
- Teste de regressão — verifica que a correção (ou qualquer mudança) não quebrou algo que já funcionava antes.
Como são executados com alta frequência e evoluem devagar, são fortes candidatos a automação — mas vale lembrar a pirâmide: a automação deve começar pelos níveis de baixo (Unidade/Integração), não pelo topo.
| Nível | Exemplo de teste relacionado à mudança |
|---|---|
| Componente | Testes de regressão automatizados por componente, incluídos na esteira de integração contínua |
| Integração de componentes | Confirmar que uma correção de interface não quebrou o repositório de código |
| Sistema | Reexecutar todos os testes de um fluxo sempre que qualquer tela daquele fluxo mudar |
| Integração de sistema | Reexecutar diariamente os testes de interação com o microsserviço externo, como parte do deploy contínuo |
| Aceite | Reexecutar os testes que antes falharam, depois que o defeito encontrado na aceitação for corrigido |
Por que isso é um eixo, não mais um nível
Uma estratégia de teste madura pensa numa matriz: nível (Unidade/Integração/Sistema/Aceite) cruzado com tipo (funcional/não funcional/caixa-branca/caixa-preta/baseado em experiência/relacionado à mudança) — não numa lista linear. As técnicas formais de como derivar casos de teste caixa-preta e caixa-branca (particionamento de equivalência, valor-limite, cobertura de código)
Por que essa ordem importa
O objetivo geral de cada nível anterior é evitar que defeitos escapem para o nível seguinte — ou pior, para produção. Um defeito pego no teste de unidade nunca chega a custar o que custaria se fosse pego só no teste de aceite (o Módulo 1 já mostrou essa curva de custo crescente com números).
Pense em cada nível como uma barreira sequencial: o trabalho dele é não deixar o defeito passar para a próxima camada. É a mesma curva de custo do Módulo 1, só que aplicada à pirâmide — um defeito pego na Unidade custa cerca de 1x; o mesmo defeito, pego só na Aceite (ou pior, em produção), pode custar perto de 100x.
Este módulo ficou só na famíliarização com os níveis — como escrever, automatizar e organizar testes em cada um deles na prática (com código C#/xUnit do projeto).


Top comments (0)