Do palpite à prova

Um supervisor relata: “aprovar uma ordem às vezes fecha a OS errada”. A primeira explicação da equipe é “o usuário clicou duas vezes”. Um programador aumenta o debounce do botão, o sintoma desaparece numa demonstração e o ticket é encerrado. Dias depois, o erro volta por uma integração que nem usa o botão.

O problema não foi falta de inteligência. Foi falta de prova. A equipe misturou sintoma, hipótese e causa; mudou várias condições; não registrou esperado versus observado; e não deixou um teste capaz de impedir a recorrência.

Teste é comparação, não cerimônia

Um teste prepara uma situação, executa um comportamento, observa um resultado e o compara com um oráculo. Oráculo é a regra que decide o que deveria acontecer: requisito, cálculo independente, contrato, fixture revisada, estado do banco ou decisão de especialista.

Dado      supervisor do shopping-a e OS 742 do shopping-b
Quando    solicita aprovação pela API
Esperado  403; estado PENDING; nenhum evento approved
Observado 200; estado APPROVED; evento gravado

Sem esperado explícito, existe execução, não teste. assert resposta is not None pode deixar a regra errada passar. Um bom assert observa consequência relevante: retorno, estado e efeito proibido.

O ISTQB Certified Tester Foundation Level organiza fundamentos como test basis, objetivos, níveis e técnicas. Neste livro, a ideia prática é mais importante que decorar termos: qual risco esta prova detecta e qual fronteira ela realmente atravessa?

Expected versus observed

Expected é o comportamento previsto pelo contrato antes da execução. Observed é o que efetivamente ocorreu. Um relato reproduzível inclui:

  • versão ou commit;
  • ambiente e configuração não secreta;
  • estado inicial mínimo;
  • ação exata;
  • esperado;
  • observado;
  • frequência, como 10/10 ou 1/20;
  • artefatos: saída do teste, log redigido, trace ou diff de estado.

Evite “não funciona”. Prefira “com OS de outro tenant, POST /approval retorna 200 em 10/10 tentativas; deveria retornar 403, e a versão passa de 3 para 4”. Essa precisão já exclui várias histórias.

Hipótese, reprodução e experimento

Uma hipótese é uma explicação que pode ser contrariada por observação. “Deve ser cache” é palpite; “o cache devolve uma OS sem tenant e por isso a policy recebe alvo incompleto; desativar apenas o cache deverá mudar o primeiro valor divergente” é testável.

O método de Effective Troubleshooting do Google SRE descreve investigação como ciclo hipotético-dedutivo: observar, formular causas possíveis e buscar evidência que confirme ou refute. O próprio guia recomenda expected, actual e reprodução num problem report, além de simplificar e examinar interfaces entre componentes.

Sequência causal

Fluxo: Sintoma relatado, Reprodução mínima, Expected × observed, Hipóteses concorrentes, Experimento discriminante, Primeira fronteira divergente, Correção mínima da causa, Regressão antes/depois, Pacote de evidênciaSintoma relatadoReprodução mínimaExpected × observedHipóteses concorrentesExperimentodiscriminantePrimeira fronteiradivergenteCorreção mínima da causaRegressão antes/depoisPacote de evidência
Ler o fluxo em texto
  1. 1. Sintoma relatado
  2. 2. Reprodução mínima
  3. 3. Expected × observed
  4. 4. Hipóteses concorrentes
  5. 5. Experimento discriminante
  6. 6. Primeira fronteira divergente
  7. 7. Correção mínima da causa
  8. 8. Regressão antes/depois
  9. 9. Pacote de evidência

Uma reprodução mínima remove ruído sem remover a falha. Se o defeito ocorre com uma chamada direta à policy, navegador e rede não são necessários para diagnosticar. Se só ocorre com duas instâncias e fila real, reduzi-lo a unitário pode apagar a condição causal.

Crie pelo menos duas hipóteses plausíveis. Para a aprovação indevida:

  • H1: a interface envia tenant errado;
  • H2: a API recebe tenant certo, mas a policy compara apenas o papel;
  • H3: a policy nega, mas o repositório grava antes da decisão.

Registre valores nas fronteiras UI → API, API → policy e policy → repositório. Se o request chega correto e policy_decision=allow para tenants diferentes, H1 perde força e a primeira divergência aponta para H2. Trocar UI, API e banco simultaneamente faria o sintoma sumir sem atribuir causa.

Quatro níveis, quatro perguntas

Os nomes variam entre comunidades; use a interface exercitada como referência.

Teste unitário

Verifica uma unidade de comportamento pequena e rápida, geralmente em processo. Para can_approve(user, order), percorra papel, tenant e estado. Unitário localiza regras e bordas com feedback rápido.

Ele não prova wiring. A policy pode estar correta e a rota nunca chamá-la. Unidade não significa necessariamente “uma função” nem exige mock de cada colaborador; significa escopo controlado com causa fácil de localizar.

Teste de integração

Verifica colaboração em uma fronteira real: serviço + banco, API + autenticação, consumer + broker ou aplicação + filesystem. No caso de autorização, chame o adapter com identidade de teste e um repositório representativo; confirme 403, estado inalterado e ausência de auditoria de sucesso.

Quanto mais fiel a dependência, mais confiança e mais custo de ambiente. Use a integração onde incompatibilidade, transação ou configuração são o risco.

Teste de contrato

Verifica se consumidor e provedor concordam sobre mensagens: método, campos, tipos, status e semântica relevante. Ele detecta que o ERP mudou workOrderId para id sem precisar executar toda a jornada visual. A documentação do Pact mostra contratos dirigidos pelo consumidor gerados nos testes do cliente e verificados contra o provedor real.

Contrato não prova regra interna nem disponibilidade. Um provedor pode retornar o JSON correto e aprovar o tenant errado.

Teste ponta a ponta — E2E

Percorre uma jornada pelas superfícies implantadas: navegador, API, identidade e banco. Protege “supervisor abre OS, aprova e vê confirmação”. O Playwright recomenda testar comportamento visível ao usuário e isolar casos, em vez de depender de classes CSS e detalhes internos.

E2E encontra wiring que níveis baixos não veem, mas é mais lento, caro e difícil de diagnosticar. Preserve poucas jornadas críticas; empurre combinações e bordas para níveis menores. Pirâmide é heurística de custo e feedback, não quota universal, como discute The Practical Test Pyramid.

Risco Primeira prova adequada Complemento
cálculo de prioridade unitário/propriedade exemplos revisados pelo domínio
policy não compara tenant unitário da policy integração negativa da API
cliente e ERP divergem contrato consumidor/provedor integração homologada
botão não aciona a rota correta E2E da jornada crítica unitários da regra
transação grava parcialmente integração com banco teste de recuperação

Test doubles: controlar dependência sem fabricar a verdade

Test double é substituto usado no teste. A taxonomia clássica inclui:

  • stub: devolve respostas programadas;
  • fake: implementação simplificada que funciona, como repositório em memória;
  • mock: verifica interações esperadas, como “publicou uma vez”;
  • spy: registra chamadas para inspeção;
  • dummy: apenas preenche um parâmetro não utilizado.

Os termos são explicados em Mocks Aren't Stubs, de Martin Fowler. Bibliotecas às vezes chamam todos de “mock”; o comportamento importa mais que o nome.

Substitua dependências lentas, caras, instáveis ou fora do escopo. Não substitua a regra que deseja provar. Este teste é fraco:

mock_policy.allow = false
chamar serviço
assert resposta == 403

Ele prova que o serviço transforma false em 403, não que a policy nega outro tenant. Execute a policy real e use um fake apenas para persistência. Depois acrescente uma integração que confirme o wiring. Um fake de ERP precisa de contract test contra o provedor; caso contrário, pode implementar um contrato imaginário.

Mocks de cada chamada interna acoplam o teste à implementação: refatorar sem mudar comportamento quebra a suíte. Observe saídas e estado sempre que possível; use verificação de interação quando a interação é o contrato, como “não publicar evento após negação”.

Cobertura: mapa de alcance, não certificado

Cobertura informa quais linhas ou branches foram executados. Ela ajuda a encontrar zonas nunca exercitadas e a acompanhar risco, mas não avalia a força do oráculo.

def can_approve(user, order):
    return user.role == "supervisor"  # esqueceu o tenant

def test_runs_the_function():
    can_approve(supervisor, foreign_order)  # sem assert: linha coberta

É possível atingir cobertura alta com asserts irrelevantes, casos apenas nominais ou mocks que desviam da produção. A pergunta melhor é: “se a condição de segurança for removida, algum teste falha?”.

Não persiga 100% indiscriminadamente. Código gerado, getters triviais e tratamento defensivo podem distorcer custo. Defina metas como sinal por área de risco, examine branches e combine com revisão, mutação e incidentes. Cobertura baixa é alerta; cobertura alta não é absolvição.

Mutation testing e mutação mental

Mutation testing altera sistematicamente o código de produção e executa a suíte. Trocar == por !=, remover uma condição ou devolver constante produz um mutante. Se um teste falha, ele foi morto; se tudo permanece verde, ele sobreviveu e indica possível lacuna.

A documentação do Stryker define esse ciclo e suas métricas. Mutation score é útil, mas também limitado: há mutantes equivalentes, custo alto e operadores artificiais. Não transforme 100% em objetivo universal.

Para iniciantes, use mutação mental na revisão: “se eu trocar and por or, remover a comparação de tenant ou publicar antes de autorizar, qual teste ficará vermelho?”. Se a resposta for “nenhum”, escreva o oráculo que falta. Isso não substitui uma ferramenta, mas ensina sensibilidade da suíte.

Corrigir causa e preservar regressão

Um teste de regressão captura o defeito para impedir que volte. A evidência mais forte executa o mesmo teste:

  1. na versão defeituosa: falha pela razão esperada;
  2. após a correção mínima: passa;
  3. com um mutante que restaura o defeito: volta a falhar.

Escreva ou confirme o vermelho antes de refatorar. Depois corrija apenas a primeira causa demonstrada. Melhorias estruturais vêm em mudança separada. Se cinco componentes mudam e o sintoma desaparece, a correlação existe, mas a atribuição continua incerta.

“Causa raiz” pode ser simplificação em sistemas complexos: condição de corrida, dados e retry podem atuar juntos. Declare o nível de confiança e fatores contribuintes. Durante incidente grave, primeiro contenha dano e preserve evidência; investigar não justifica manter corrupção ativa, como alerta o guia de troubleshooting do Google SRE.

Evidência independente para código produzido por IA

O modelo que escreveu a função pode explicar por que ela “parece correta”, mas isso não cria oráculo independente. Use ferramentas e fontes com caminhos de erro diferentes:

  • testes executáveis contra contrato versionado;
  • typecheck, lint e análise de segurança;
  • baseline antes da alteração;
  • diff revisável;
  • integração e outcome real em ambiente controlado;
  • revisão humana por risco;
  • eval calibrada quando a saída é probabilística.

Pedir três vezes ao mesmo modelo para confirmar repete a mesma fonte. Um juiz por modelo pode ajudar em critérios semânticos, mas não substitui um assert de estado ou autorização. O NIST SSDF enquadra verificação como prática contínua do ciclo seguro; código gerado por IA não recebe exceção.

Pacote de evidência

Uma entrega reproduzível contém:

Problema: expected, observed, frequência, impacto
Ambiente: commit, runtime, configuração não secreta
Hipóteses: H1, H2, H3 e evidência contra/a favor
Reprodução: fixture e comando mínimo
Fronteira: primeira divergência observada
Correção: diff pequeno e justificativa causal
Provas: vermelho antes, verde depois, casos negativos
Escopo: unit/integration/contract/E2E executados
Limites: o que ainda não foi provado
Operação: rollback, monitoramento e risco residual

Screenshot sem comando, estado e versão é fraco. Logs podem sustentar a linha do tempo, mas devem omitir senha, token e dado pessoal. Traces conectam fronteiras distribuídas; a especificação OpenTelemetry padroniza sinais, não decide quais conclusões seu domínio permite.

Troubleshooting prático

  • Falha só no CI: compare runtime, timezone, ordem, paralelismo, recursos e dependências; aumentar timeout primeiro mascara causa.
  • Teste flaky: controle relógio, aleatoriedade e estado; retry mede frequência, não corrige determinismo.
  • Unitário passa, API falha: investigue wiring, serialização, autenticação e transação com integração.
  • E2E falha sem pista: reproduza num nível menor e use trace para localizar a primeira fronteira.
  • Mock sempre verde: execute contrato contra implementação real ou substitua mock por fake/integrador representativo.
  • Cobertura sobe, defeitos não caem: revise asserts, negativos, limites e mutantes sobreviventes.
  • Correção não reproduz o vermelho: teste pode estar observando o sintoma errado; não o chame de regressão ainda.

Critérios de aceite e exercício

Você domina esta etapa quando consegue escrever expected/observed, reduzir uma reprodução, propor hipóteses concorrentes, escolher nível por risco, justificar cada double, mostrar limite da cobertura, matar mentalmente um mutante e produzir evidência antes/depois.

Como exercício, use o caso de aprovação entre tenants. Escreva um unitário da policy, uma integração da rota, um contrato da resposta 403 e uma jornada E2E nominal. Para cada um, diga o que prova e o que não prova. Depois imagine remover a comparação de tenant: identifique quais testes devem falhar. Execute o Caderno operacional para produzir o pacote completo.

Recuperação ativa

  1. Qual é a diferença entre expected, observed e hipótese?
  2. Um teste executa todas as linhas sem assert significativo. O que a cobertura prova?
  3. Por que mockar a policy não testa a regra de autorização?
  4. Quando um teste de contrato é melhor que um E2E?
  5. O que significa um mutante sobreviver?
  6. Por que mudar cinco componentes enfraquece a atribuição causal?
  7. Qual evidência evita usar a IA como único juiz do próprio código?

Fontes e relações

As definições operacionais são apoiadas pelo syllabus atual do ISTQB, pela metodologia causal do Google SRE e pelas documentações oficiais de Pact, Playwright e Stryker. Ferramentas exemplificam práticas; não substituem a análise de risco.

Depois deste livro, conecte o pacote de evidência ao fluxo de implementação e revisão. Para sistemas probabilísticos, reutilize a mesma distinção entre oráculo, baseline, segmentos e outcome na trilha de evals.

Teste de fixação

Comprove o que você aprendeu

Responda todas as questões. O gabarito comentado só aparece depois do envio.

1. Um teste executa todas as linhas, mas não possui assert significativo. O que a cobertura prova?
2. Uma correção altera cinco componentes e o sintoma desaparece. Por que a causa continua incerta?
3. Qual desenho evita usar o modelo como único juiz do código ou resposta que ele próprio produziu?

Consulta universal

O que você quer encontrar?

Títulos, capítulos, conceitos, termos, laboratórios e ferramentas em uma única busca.

Digite pelo menos dois caracteres.