#desenvolvimento-de-software
#produto
#fundadores
Opinião

Cobertura de teste alta é o disfarce favorito do bug em produção

Recebi um print de 92% de cobertura no mesmo dia em que o checkout do cliente estava quebrado. Coverage mede linha que rodou, não resultado que alguém conferiu, e virou o número mais fácil de um fornecedor maquiar. O que um squad sênior olha antes de confiar no verde.

Por Raquel Reis

Analista de dados, pós-graduada em Ciência de Dados e engenheira eletricista de formação.

Um fundador de fintech me mandou um print numa quinta à noite. Era o relatório de testes do fornecedor dele: 92% de cobertura, tudo verde, aquele selo que dá orgulho de colar no README. Na mesma imagem, aberta em outra aba, a tela de checkout do produto congelada. Ele não é cliente da Revin. Tinha me procurado por indicação, querendo uma segunda opinião antes de renovar o contrato com quem construiu aquilo.

A pergunta dele era honesta e desconfortável: como é que 92% de cobertura deixa o checkout cair? A resposta cabe numa frase, e é a origem de metade dos sustos que vejo em produção. Cobertura de teste não mede se o seu software funciona. Mede quantas linhas foram executadas enquanto os testes rodaram. São coisas diferentes, e a distância entre as duas é onde o bug se esconde.

Um teste pode percorrer todo esse componente, imprimir o valor no console e nunca conferir se ele está certo.

Um teste pode percorrer todo esse componente, imprimir o valor no console e nunca conferir se ele está certo.

O que a cobertura de teste de fato conta

Coverage é uma métrica de execução. A ferramenta instrumenta o código, roda a sua suíte e marca cada linha, cada branch e cada função tocada pelo menos uma vez. No fim divide o que foi tocado pelo total e devolve uma porcentagem. Isso serve bem pra uma coisa: achar o código que nenhum teste chega perto. Um trecho com 0% é um alerta de verdade.

O problema é o que ela ignora. A métrica registra que a linha rodou. Se alguém conferiu o resultado daquela linha, ela não faz ideia. Um teste que chama calcularJuros(saldo) e não olha o retorno marca a função como coberta do mesmo jeito. A função rodou. O valor que saiu dela ficou sem revisão. No painel, o verde é idêntico ao de um teste que confere centavo por centavo.

Foi mais ou menos o que encontramos na suíte da fintech. Boa parte dos testes exercitava o código e parava ali, sem nunca perguntar se o resultado batia com o esperado.

Como um teste roda, passa e não verifica nada?

Existem três jeitos comuns de um teste ficar oco. Nenhum deles aparece na porcentagem de cobertura:

  • Teste sem asserção: chama a função e não usa nenhum expect. Se não estourar uma exceção, passa. Cobre a linha e não valida o comportamento.
  • Mock demais: o teste simula tanta dependência que acaba conferindo o próprio mock. Você programa a resposta e, três linhas depois, verifica que a resposta é aquela que você mesmo programou.
  • Snapshot no automático: o teste compara a saída com um retrato salvo. Quando quebra, muita gente roda o update sem pensar, o retrato vira a nova verdade e o teste volta ao verde sem ninguém ler o diff.

Os três inflam a cobertura e não seguram nada. Como o número sobe, todo mundo se sente mais seguro. Inclusive o fornecedor, que passa a reportar o 92% como se porcentagem fosse a mesma coisa que qualidade.

Pegar um teste e perguntar 'o que acontece se eu quebrar essa linha de propósito?' revela mais do que qualquer porcentagem no relatório.

Pegar um teste e perguntar 'o que acontece se eu quebrar essa linha de propósito?' revela mais do que qualquer porcentagem no relatório.

O número que o bodyshop adora colar no slide

Cobertura virou métrica de vendas. Sobe fácil, porque escrever teste sem asserção é rápido. Cabe num número redondo. E impressiona quem não lê código. Para uma agência que fatura por entrega, é o indicador perfeito: cresce quase sozinho e o cliente não tem como contestar de fora.

O incentivo aí é torto. Quando o contrato paga por feature entregue com testes, o fornecedor otimiza pra bater a porcentagem. Prevenir o incidente de produção é outro trabalho, mais chato e mais caro, que ninguém está pagando explicitamente. Não é que estejam mentindo. Estão medindo a coisa fácil e cobrando por ela.

Num squad sênior, o teste é revisado como código de produção. Um pull request que adiciona teste sem asserção não passa no review: ele volta com a pergunta "o que isso está garantindo?". É assim que a gente cuida das suítes dos clientes na Revin, e é o que separa uma cobertura que te protege de uma que só te enfeita. Se ninguém nunca revisou os seus testes com esse rigor, começa por um raio-x honesto do que existe hoje.

🧬 Mutação: quem testa os seus testes

Tem uma técnica antiga e pouco usada que mira exatamente esse ponto cego: teste de mutação. A ideia é quase perversa. Uma ferramenta pega o seu código e planta bugs de propósito: troca um > por >=, inverte uma condição, apaga uma linha ou transforma um + em -. Cada versão estragada é um mutante, e a suíte inteira roda contra cada um deles.

A leitura é direta. Se o código foi quebrado e nenhum teste reclamou, aquele teste não estava protegendo nada: o mutante sobreviveu. O que importa deixa de ser quantas linhas você cobre e passa a ser quantos desses bugs plantados a sua suíte consegue matar. Ferramentas como Stryker, no mundo JavaScript e TypeScript, e PIT, em Java, fazem isso e devolvem um mutation score.

Rodamos o Stryker naquela suíte de 92%. O mutation score deu 41%. Traduzindo: mais da metade dos bugs que plantamos de propósito passou reto pelos testes verdes. Esse número oscila conforme a ferramenta e o que você manda ela mutar, admito. Não trato 41% como lei da física. Mas mesmo cortando uma margem generosa, a conclusão não muda: a suíte confortável cobria bastante e, na hora de segurar um bug real, deixava passar. Esse é o tipo de leitura que a gente faz nos primeiros dias com um cliente, e alguns viram caso publicado depois.

O verde que vale é o que você consegue quebrar

Se você é fundador, não peça a porcentagem de cobertura. Ela vem alta e não te conta nada. Pergunte outra coisa pro seu time ou pro seu fornecedor: o que acontece com a suíte se alguém quebrar uma regra de negócio de propósito? Se a resposta for silêncio, ou um 'a gente confia nos noventa e poucos por cento', você já tem o diagnóstico.

Vou ser justa. Nem todo projeto precisa disso. Um site institucional de cinco páginas nunca vai montar teste de mutação, e está ótimo assim: ali cobertura alta já resolve, e contratar um squad sênior seria desperdício do seu dinheiro. Agora, qualquer coisa que mexe com dinheiro, com dado sensível ou com um fluxo que derruba a operação inteira quando cai, o número bonito sozinho é teatro.

O fundador da fintech não trocou de fornecedor por raiva. Trocou porque, pela primeira vez, alguém sentou com ele e mostrou na prática o quanto aquela suíte confortável realmente defendia o produto dele. Era pouco. Se você desconfia que a sua cobertura está mais pra enfeite, o primeiro passo é olhar de verdade o que a sua suíte garante hoje, e esse raio-x cabe numa conversa.

Pronto para elevar o seu negócio?

Agendar uma reunião
Compartilhe
Link de compartilhamento LinkedinLink de compartilhamento XLink de compartilhamento WhatsappLink de compartilhamento Facebook
Você também pode gostar

A cada quinze dias. As decisões técnicas que tomamos, e o que aprendemos.