Por que testar em Go não é assustador, mas necessário
\n\nQuando você escreve em Go pela primeira vez, parece que o compilador pega quase tudo: os tipos são rigorosos, os erros são explícitos, nil está sob controle. Mas quando seu projeto cresce para mais de 500 linhas, você percebe: sem testes não dá para viver. Uma alteração em um lugar quebra outro, e você só descobre isso em produção.
Neste artigo, mostrarei por onde começar a testar em Go para um desenvolvedor iniciante. Vamos abordar testes unitários, testes tabelados, mocks e cobertura de código. Sem enrolação — apenas exemplos práticos e dicas úteis.
\n\nSe você escreve em Go há pelo menos alguns meses, este material economizará horas de depuração.
\n\nO que você precisa saber antes de começar
\n\nGo fornece o pacote nativo testing — não é necessário instalar nada adicional. Os testes são escritos em arquivos com o sufixo _test.go e executados com o comando:
go test ./...\n\nRegras básicas:
\n- \n
- A função de teste deve ser chamada
TestXxx(t *testing.T), onde Xxx é o nome da função testada com letra maiúscula. \n - Os arquivos de teste ficam junto ao código testado. \n
- Erros são reportados via
t.Error()out.Fatal(). \n
Vamos direto à prática.
\n\nEscrevendo o primeiro teste unitário em Go
\n\nSuponha que temos uma função simples que soma dois números:
\n\n// calc.go\npackage calc\n\nfunc Sum(a, b int) int {\n return a + b\n}\n\nCriamos o arquivo calc_test.go na mesma pasta:
// calc_test.go\npackage calc\n\nimport "testing"\n\nfunc TestSum(t *testing.T) {\n result := Sum(2, 3)\n expected := 5\n\n if result != expected {\n t.Errorf("Sum(2,3) = %d; want %d", result, expected)\n }\n}\n\nExecutamos o teste:
\n\ngo test -v\n\nVocê verá um PASS verde — sua primeira vitória nos testes. Observe: usamos t.Errorf (não fatal) — o teste continua mesmo se um caso falhar.
Testes tabelados: quando um único teste não é suficiente
\n\nImagine que você precisa testar uma função com dezenas de entradas diferentes. Escrever 10 testes separados? Não, em Go existe o teste tabelado (table-driven test). É o padrão da comunidade Go.
\n\nVamos adicionar uma função de divisão ao nosso calc.go:
func Divide(a, b int) (int, error) {\n if b == 0 {\n return 0, errors.New("division by zero")\n }\n return a / b, nil\n}\n\nAgora escrevemos o teste tabelado:
\n\nfunc TestDivide(t *testing.T) {\n tests := []struct {\n name string\n a, b int\n expected int\n wantErr bool\n }{\n {"positive", 10, 2, 5, false},\n {"negative", -6, 3, -2, false},\n {"zero division", 5, 0, 0, true},\n {"same numbers", 7, 7, 1, false},\n }\n\n for _, tt := range tests {\n t.Run(tt.name, func(t *testing.T) {\n got, err := Divide(tt.a, tt.b)\n if tt.wantErr {\n if err == nil {\n t.Error("expected error, got nil")\n }\n return\n }\n if err != nil {\n t.Errorf("unexpected error: %v", err)\n }\n if got != tt.expected {\n t.Errorf("Divide(%d,%d) = %d; want %d", tt.a, tt.b, got, tt.expected)\n }\n })\n }\n}\n\nO que há de legal aqui:
\n- \n
- Cada caso é um subteste com nome. Se um falhar, os outros continuam. \n
- Fácil adicionar novos casos — basta incluir uma linha na struct. \n
- O código lê-se como uma especificação. \n
Execute com a flag -v — você verá os nomes de todos os subtestes. Muito útil na depuração.