Introdução: por que TDD não é uma religião, mas sim uma tábua de salvação
\n\nImagine que você está consertando a fiação elétrica em uma casa antiga. Você desliga o disjuntor, mas ainda assim tem medo de colocar as mãos no quadro. É mais ou menos assim que se sente um desenvolvedor que faz alterações em um projeto sem testes. Especialmente em Go — uma linguagem onde a tipagem estática dá uma falsa sensação de segurança.
\n\nDesenvolvimento Orientado a Testes (TDD) em Go não é uma tendência da moda nem um ritual sectário. É uma metodologia que transforma o medo da refatoração em confiança. De acordo com um estudo da IBM, projetos com TDD apresentam 40% menos defeitos. E em Go, onde o compilador já elimina metade dos erros, o TDD elimina os 50% restantes.
\n\nNeste artigo, não vamos dar palestras. Vamos pegar um problema real: escrever um pequeno serviço HTTP para encurtar links. E percorreremos todo o caminho do TDD — do teste vermelho ao verde e à refatoração. Vamos nessa!
\n\nO que é TDD de verdade?
\n\nSe você já ouviu falar sobre Red-Green-Refactor, já está por dentro. Se não, lembre-se de três passos simples:
\n\n- \n
- Red — escrevemos um teste que sabemos que vai falhar (porque a funcionalidade ainda não existe). \n
- Green — escrevemos o código mínimo para o teste passar. Não o ideal, apenas algo que funcione. \n
- Refactor — melhoramos o código sem alterar seu comportamento. Os testes são nossa segurança. \n
Em Go, esse ciclo é especialmente agradável graças ao pacote embutido testing. Você não precisa instalar jest ou pytest — tudo já está na biblioteca padrão. Mas muitos iniciantes ignoram os testes, achando que Go já é "seguro" por si só. E é um erro.
Por que o TDD em Go funciona melhor do que em outras linguagens?
\n\nA comunidade Go adora simplicidade. Aqui, o TDD não se transforma em burocracia com mocks e stubs. Em vez disso, você escreve testes orientados a tabela (table-driven tests) — compactos, legíveis e compreensíveis. Um caso de teste — uma linha. E sim, os testes em Go são rápidos. Milissegundos para centenas de casos é normal.
\n\nA propósito, no blog oficial do Go, eles enfatizam repetidamente: "Testes são documentação". Se o seu teste é lido como uma especificação, você está fazendo tudo certo.
\n\nConfigurando o ambiente: o que você precisa para começar
\n\nPresumo que você já tenha o Go instalado. Se não: brew install go ou apt install golang-go. Verifique a versão: go version. Para este artigo, Go 1.21+ é suficiente.
Vamos criar o projeto:
\n\nmkdir url-shortener-tdd\ncd url-shortener-tdd\ngo mod init url-shortener\n\nPronto. Nada de frameworks — apenas a biblioteca padrão e desenvolvimento orientado a testes em Go.
\n\nEscrevendo o primeiro teste: Red
\n\nSuponha que queremos uma função Shorten(url string) string, que transforma uma URL longa em um hash curto. Ela ainda não existe — e isso é ótimo. Vamos escrever o teste:
// shortener_test.go\npackage main\n\nimport "testing"\n\nfunc TestShorten(t *testing.T) {\n url := "https://pythonlib.ru/very/long/path?with=params&and=stuff"\n result := Shorten(url)\n\n if len(result) == 0 {\n t.Error("Shorten retornou uma string vazia")\n }\n\n if len(result) > 10 {\n t.Errorf("Esperava um hash curto, mas obteve %d caracteres", len(result))\n }\n}\n\nExecutamos: go test -v. Vemos vermelho (bem, tecnicamente — um erro de compilação). A função Shorten não existe. Ótimo, estamos na fase Red.
Código mínimo: Green
\n\nAgora escrevemos exatamente o suficiente para o teste passar. Nada de criptografia, apenas um hash:
\n\n// shortener.go\npackage main\n\nimport (\n "crypto/sha256"\n "fmt"\n)\n\nfunc Shorten(url string) string {\n hash := sha256.Sum256([]byte(url))\n return fmt.Sprintf("%x", hash[:4]) // pegamos os primeiros 4 bytes\n}\n\nExecutamos o teste novamente. Verde? Perfeito. Mas o código é horrível — o hash tem colisões, e nem sequer verificamos se