A maioria dos programadores escreve testes para provar que o código funciona. Isso é útil, mas não é a coisa mais interessante que os testes podem fazer por ti.
Eu costumava escrever testes depois de tudo feito. Construir a coisa, fazê-la funcionar, adicionar testes para o pipeline de CI não reclamar. Os testes passavam. O código era entregue. Ficava satisfeito com isso.
Depois comecei a prestar atenção ao que acontecia quando escrever os testes era genuinamente doloroso. Não apenas tedioso, mas desconfortável. O tipo de atrito que te faz questionar as tuas escolhas. Esse desconforto acabou por ser um sinal útil.
O Teste Está a Tentar Dizer-Te Algo
Quando um teste é difícil de escrever, quase sempre há uma razão. A função faz demasiado. As dependências estão entrelaçadas por dentro em vez de serem passadas como argumento. O resultado depende de estado global que não percebias que existia. A interface fazia sentido quando a estavas a construir, mas de fora, como utilizador, é estranha.
Os testes obrigam-te a ser utilizador do teu próprio código. Essa mudança de perspetiva é subestimada. Deixas de pensar na implementação e começas a pensar no uso. São perguntas diferentes, e muitas vezes têm respostas diferentes.
Uma função difícil de testar é geralmente difícil de usar. Nem sempre, mas é uma heurística suficientemente fiável para levar a sério.
O Que Muda Quando Escreves os Testes Primeiro
O desenvolvimento orientado por testes recebe muito entusiasmo e uma boa dose de críticas. Algumas das críticas são merecidas. O TDD estrito pode parecer mais um ritual do que uma ferramenta, e muitas pessoas aplicam-no mecanicamente sem tirar muito partido.
Mas a ideia central é sólida: se esboçares como queres chamar algo antes de o construir, acabas com uma interface melhor.
É a mesma razão pela qual escrever documentação antes do código às vezes ajuda. És forçado a descrever o que a coisa faz sem saber exatamente como o faz. Essa restrição é produtiva.
Nem sempre escrevo testes primeiro. Às vezes preciso de explorar o problema antes de saber qual é a interface certa. Código exploratório é aceitável, só não o confundas com código de produção. Quando percebo a forma do problema, muitas vezes descarto o primeiro rascunho e começo de novo com os testes a liderar.
As Coisas Específicas Que os Testes Revelam
Com o tempo, notei alguns padrões no que os testes dolorosos tentam dizer-me.
Se a configuração de um único teste leva vinte linhas, a função tem demasiadas dependências. O teste está a refletir o custo real de usar aquele código. Está apenas a torná-lo visível de uma vez em vez de o esconder por todo o código base.
Se tenho de simular metade do mundo para testar uma coisa, as minhas abstrações estão a vazar. O código sabe demasiado sobre o seu ambiente. Passar dependências como argumento em vez de as ir buscar torna o código e os testes mais simples.
Se não consigo descrever o que um teste verifica numa frase, a função provavelmente faz mais do que uma coisa. Divide-a. Os testes ficam mais claros, e o código também.
Testes como Documentação
Os bons testes são também uma das melhores formas de documentação, porque não mentem. Os comentários ficam desatualizados. Os READMEs derivam. Os testes, se estiverem no pipeline de CI, têm de se manter verdadeiros ou a build quebra.
Um teste que mostra como construir os inputs, chamar a função e verificar o output é muitas vezes mais útil do que um parágrafo de texto a explicar o que a função faz. Podes executá-lo. Podes modificá-lo. Podes usá-lo como ponto de partida.
Isto só funciona se os testes forem legíveis. Um teste cheio de números mágicos e configuração opaca não documenta nada. Escreve testes da mesma forma que escrevias um exemplo na documentação: mínimo, claro, focado num único comportamento.
O Hábito Que Vale a Pena Construir
Não estou a defender o TDD estrito, 100% de cobertura ou qualquer metodologia em particular. Estou a defender que prestes atenção quando escrever testes é difícil.
Esse atrito é feedback. É o teu código a dizer-te algo sobre si mesmo. Aprender a ler esse sinal, em vez de o ignorar ou de o atravessar à força, é uma das competências mais práticas que podes desenvolver como programador.
Os testes mais fáceis de escrever são geralmente os de código mais fácil de manter. Não é coincidência.



