DEV Community

Yuri Peixinho
Yuri Peixinho

Posted on

Fases e Níveis de Teste

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)