Pular para o conteudo principal

Como Escrever Testes que Não Quebram por Qualquer Detalhe Interno

Como evitar testes frágeis que falham porque você reorganizou código, renomeou método ou mudou uma implementação sem alterar o comportamento real.

Andrews Ribeiro

Andrews Ribeiro

Founder & Engineer

O problema

Tem teste que parece útil até o dia em que você melhora o código.

Você:

  • extrai função
  • muda ordem interna
  • troca uma estrutura de dados
  • remove uma chamada intermediária

E a suíte explode.

Não porque o comportamento que importa mudou.

Mas porque o teste estava apegado demais à implementação antiga.

Esse tipo de teste não protege evolução.

Ele pune evolução.

Modelo mental

Pense assim:

teste bom verifica o que o sistema promete. Teste frágil verifica como ele estava fazendo isso ontem.

Essa diferença é tudo.

Se o teste depende de:

  • ordem exata de chamadas internas
  • número de métodos privados acionados
  • estrutura intermediária irrelevante
  • detalhes de montagem que o usuário nunca vê

ele deixa de ser rede de segurança e vira alarme falso.

Quebrando o problema

Prefira comportamento observável

A pergunta útil é:

se isso mudar, quem realmente vai sentir?

Boas respostas costumam ser:

  • valor retornado
  • estado persistido
  • evento publicado
  • erro exibido
  • efeito visível para outra parte do sistema

Más respostas costumam ser:

  • quantas funções privadas rodaram
  • em que ordem três helpers internos se chamaram
  • que variável temporária existia no meio do caminho

Cuidado com espiar tudo

Spy, stub e mock têm lugar.

O problema começa quando o teste usa esses recursos para observar cada passo da coreografia interna.

Aí qualquer refatoração simples vira “regressão”.

O teste continua verde enquanto a estrutura antiga existe.

Mas já não está te ajudando a melhorar nada.

Teste no nível certo da promessa

Se a promessa da função é:

  • calcular um total
  • validar uma regra
  • persistir um registro
  • publicar um evento

o teste deve se prender a isso.

Se a promessa não inclui “chamar exatamente estes três métodos nesta ordem”, o teste normalmente também não deveria incluir.

Estrutura interna pode mudar sem o sistema quebrar

Esse é o ponto que muita gente esquece.

Código saudável muda por dentro o tempo todo:

  • simplifica
  • extrai
  • junta
  • reorganiza

Se cada mudança interna exige renegociar a suíte inteira, o custo de manutenção sobe demais.

Um teste pode passar e ainda estar piorando o projeto

Esse é um insight importante.

Teste frágil não é só o que falha muito.

É também o que torna o time mais conservador do que deveria:

  • ninguém quer refatorar
  • ninguém quer limpar nome ruim
  • ninguém quer mexer em duplicação

Ou seja, ele degrada o código sem parecer que está causando isso.

Exemplo simples

Imagine uma função que calcula frete.

Teste ruim:

  • espiona que normalizeZipCode foi chamado
  • verifica que getDistanceTable rodou antes de applyRegionalRule
  • falha se a implementação interna muda

Teste melhor:

  • dado CEP válido e peso X, o frete final é Y
  • dado CEP inválido, retorna erro esperado
  • dada região promocional, aplica desconto correto

O segundo conjunto protege a regra.

O primeiro protege a coreografia da versão atual.

Erros comuns

  • Confundir visibilidade interna com confiança real.
  • Escrever teste tão íntimo da implementação que ele quebra em refatoração trivial.
  • Verificar chamada de método quando o que importa é o resultado final.
  • Acoplar teste a detalhes que o comportamento público não promete.
  • Chamar de “rigor” o que na prática é medo de deixar o código mudar.

Como um senior pensa

Quem tem mais experiência costuma olhar para um teste e perguntar:

“Se eu melhorar o código por dentro sem mudar a promessa, esse teste continua fazendo sentido?”

Se a resposta for não, o teste provavelmente está acoplado demais.

Senioridade aqui aparece quando a pessoa protege comportamento e deixa a implementação respirar.

O que o entrevistador quer ver

Em entrevista, esse tema mede maturidade de manutenção, não só conhecimento de framework.

O avaliador quer ver se você:

  • diferencia comportamento de implementação
  • entende por que teste frágil atrapalha refatoração
  • sabe escolher asserts que protegem o que importa
  • evita usar spy e mock como muleta para tudo

Uma resposta forte costuma soar assim:

“Eu tento escrever teste no nível da promessa do código. Se uma refatoração interna sem mudança de comportamento quebrar o teste, geralmente é sinal de que o teste sabe demais sobre a implementação.”

Suíte madura não é a que impede o código de mudar. É a que impede o comportamento importante de quebrar.

Quando o teste vigia demais por dentro, ele para de proteger por fora.

Resumo rápido

O que vale manter na cabeça

Checklist de pratica

Use isto ao responder

Você concluiu este artigo

Artigo anterior Testes em Frontend Moderno: Estado, Async, Rede e UI

Continue explorando

Artigos relacionados