Cobertura de código com testes em Go: do "visto verde" à qualidade real
\n\nNo mundo do desenvolvimento Go, a frase "tenho 95% de cobertura" soa orgulhosa. Mas muitas vezes por trás desse número há um vazio: os testes verificam apenas o caminho feliz, enquanto casos limite e erros ficam de fora. Neste artigo, vamos entender como medir a cobertura de código com testes em Go de verdade, quais métricas são realmente importantes e quais ferramentas podem transformar os testes de uma formalidade em uma poderosa ferramenta de controle de qualidade.
\n\nNão vamos apenas recontar a documentação. Em vez disso — exemplos reais, armadilhas e dicas práticas para quem programa em Go e quer dormir tranquilo.
\n\nPor que simplesmente 80% é ruim?
\n\nSuponha que você tenha uma função:
\n\nfunc ProcessOrder(amount float64, discount bool) (float64, error) {\n if amount <= 0 {\n return 0, errors.New("amount must be positive")\n }\n if discount {\n amount *= 0.9\n }\n return amount, nil\n}\n\nVocê escreveu um teste: ProcessOrder(100, true) → 90, nil. Cobertura? 100% das linhas. Mas você não testou o caso com amount <= 0 e o caso sem desconto. Formalmente — cobertura excelente. Na prática — bugs garantidos. É por isso que as métricas de cobertura de código com testes em Go precisam ser analisadas em conjunto com outros indicadores.
Ferramentas de cobertura: do simples ao complexo
\n\n1. O nativo go test -cover
\n\nA maneira mais simples de saber a cobertura de código com testes em Go é a flag -cover:
go test -cover ./...\n\nSaída:
\nok myproject/orders 0.234s coverage: 72.3% of statements\n\nMas isso é apenas um número geral. Para ver quais linhas não estão cobertas, use -coverprofile:
go test -coverprofile=coverage.out ./...\ngo tool cover -html=coverage.out\n\nUm navegador será aberto com destaque: verde — coberto, vermelho — não. Este é o primeiro passo para entender as métricas de cobertura Go.
\n\n2. go tool cover: modos e nuances
\n\ngo tool cover suporta três modos:
- \n
- set — se a linha foi executada pelo menos uma vez (padrão) \n
- count — quantas vezes cada linha foi executada \n
- atomic — count, mas com contadores atômicos para testes paralelos \n
Para análise de cobertura de testes Golang em código multithread, use atomic, caso contrário, você corre o risco de obter contadores incorretos devido a race conditions.
\n\ngo test -covermode=atomic -coverprofile=coverage.out ./...\n\n3. Race detector — cobertura oculta
\n\nCondições de corrida (data races) são um dos principais problemas do código Go. Mesmo com 100% de cobertura de linhas, o race detector pode encontrar erros que os testes não perceberam. Execute os testes com a flag -race:
go test -race -cover ./...\n\nImportante: o race detector torna os testes 2 a 20 vezes mais lentos, mas para módulos críticos, esta é uma prática obrigatória. Inclua-o no CI para pacotes-chave.
\n\nMétricas que realmente importam
\n\nA porcentagem de cobertura de linhas é apenas a ponta do iceberg. Aqui está o que você precisa monitorar:
\n\n1. Cobertura de ramificações (branch coverage)
\n\nO go test -cover padrão conta linhas, não ramos. Para cobertura de código com testes em Go no nível de ramificações, use gocov ou go-test-coverage. Exemplo:
go get github.com/axw/gocov/gocov\ngocov test ./... | gocov report\n\nVocê verá não apenas as linhas, mas também a quantidade de condições não cobertas. Por exemplo, para uma função com dois ifs — 4 ramos, dos quais 2 estão cobertos.
\n\n2. Cobertura por mutação (mutation testing)
\n\nA maneira mais honesta de avaliar a qualidade dos testes é