Testes e Debug em Go — Referência Rápida
Go inclui ferramentas de teste, benchmark e profiling na biblioteca padrão. Esta referência cobre os padrões e comandos mais usados. Para guias completos, veja Testes em Go e Table-Driven Tests.
Estrutura de Testes
Arquivo e Convenção
| Convenção | Regra |
|---|---|
| Arquivo de teste | *_test.go (não é compilado no binário final) |
| Função de teste | func TestNome(t *testing.T) |
| Função de benchmark | func BenchmarkNome(b *testing.B) |
| Função de exemplo | func ExampleNome() |
| TestMain | func TestMain(m *testing.M) — setup/teardown global |
Teste Básico
package math
import "testing"
func TestSoma(t *testing.T) {
resultado := Soma(2, 3)
esperado := 5
if resultado != esperado {
t.Errorf("Soma(2, 3) = %d; esperado %d", resultado, esperado)
}
}
Métodos do testing.T
| Método | Descrição |
|---|---|
t.Errorf(format, ...) | Registra erro e continua |
t.Fatalf(format, ...) | Registra erro e para o teste |
t.Log(args...) | Log (só aparece com -v) |
t.Logf(format, ...) | Log formatado |
t.Skip(args...) | Pula o teste |
t.Skipf(format, ...) | Pula com mensagem formatada |
t.Helper() | Marca como helper (melhora stack trace) |
t.Parallel() | Marca para execução paralela |
t.Run(name, func) | Subteste nomeado |
t.Cleanup(func) | Registra cleanup (executa ao final) |
t.TempDir() | Diretório temporário (limpo automaticamente) |
Veja testing no glossário para conceitos fundamentais.
Table-Driven Tests
O padrão mais idiomático para testar múltiplos cenários. Veja o guia completo de table-driven tests.
package math
import "testing"
func TestDivide(t *testing.T) {
tests := []struct {
nome string
a, b float64
esperado float64
expectErr bool
}{
{nome: "divisão normal", a: 10, b: 2, esperado: 5},
{nome: "divisão decimal", a: 7, b: 3, esperado: 2.3333333333333335},
{nome: "divisão por zero", a: 10, b: 0, expectErr: true},
{nome: "ambos zero", a: 0, b: 0, expectErr: true},
}
for _, tt := range tests {
t.Run(tt.nome, func(t *testing.T) {
resultado, err := Divide(tt.a, tt.b)
if tt.expectErr {
if err == nil {
t.Fatal("esperava erro, mas não recebeu")
}
return
}
if err != nil {
t.Fatalf("erro inesperado: %v", err)
}
if resultado != tt.esperado {
t.Errorf("Divide(%.1f, %.1f) = %.4f; esperado %.4f",
tt.a, tt.b, resultado, tt.esperado)
}
})
}
}
Subtestes e t.Run
package api
import "testing"
func TestAPI(t *testing.T) {
// Setup compartilhado
srv := setupTestServer(t)
defer srv.Close()
t.Run("GET /users", func(t *testing.T) {
t.Parallel()
// testar listagem
})
t.Run("POST /users", func(t *testing.T) {
t.Parallel()
// testar criação
})
t.Run("DELETE /users/:id", func(t *testing.T) {
// testar remoção
})
}
Execute subtestes específicos com:
go test -run TestAPI/GET_/users -v
TestMain (Setup/Teardown Global)
package db
import (
"os"
"testing"
)
func TestMain(m *testing.M) {
// Setup: executado antes de todos os testes
pool := setupDatabase()
// Rodar testes
code := m.Run()
// Teardown: executado após todos os testes
pool.Close()
os.Exit(code)
}
Benchmarks
package math
import "testing"
func BenchmarkSoma(b *testing.B) {
for i := 0; i < b.N; i++ {
Soma(100, 200)
}
}
func BenchmarkConcat(b *testing.B) {
b.Run("plus", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = "hello" + " " + "world"
}
})
b.Run("sprintf", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = fmt.Sprintf("%s %s", "hello", "world")
}
})
}
// Benchmark com alocações
func BenchmarkAppend(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
s := make([]int, 0)
for j := 0; j < 100; j++ {
s = append(s, j)
}
}
}
Métodos do testing.B
| Método | Descrição |
|---|---|
b.N | Número de iterações (ajustado pelo framework) |
b.ReportAllocs() | Incluir contagem de alocações |
b.ResetTimer() | Zerar timer (usar após setup) |
b.StopTimer() / b.StartTimer() | Pausar/retomar medição |
b.Run(name, func) | Sub-benchmark |
b.SetBytes(n) | Definir throughput (bytes/op) |
Para profiling avançado, veja Performance e Profiling em Go e o guia de PGO.
Flags do go test
| Flag | Descrição | Exemplo |
|---|---|---|
-v | Verbose (mostra t.Log) | go test -v ./... |
-run REGEX | Filtrar testes por nome | go test -run TestSoma |
-count N | Repetir N vezes (desativa cache) | go test -count=1 ./... |
-race | Ativar race detector | go test -race ./... |
-cover | Mostrar cobertura | go test -cover ./... |
-coverprofile FILE | Gerar arquivo de cobertura | go test -coverprofile=c.out |
-bench REGEX | Rodar benchmarks | go test -bench=. ./... |
-benchmem | Mostrar alocações em benchmarks | go test -bench=. -benchmem |
-benchtime D | Duração do benchmark | go test -bench=. -benchtime=5s |
-timeout D | Timeout por teste | go test -timeout=30s |
-short | Habilita testing.Short() | go test -short ./... |
-parallel N | Limitar testes paralelos | go test -parallel=4 |
-shuffle on | Embaralhar ordem | go test -shuffle=on |
-failfast | Parar no primeiro erro | go test -failfast ./... |
-cpuprofile FILE | CPU profiling | go test -cpuprofile=cpu.out -bench=. |
-memprofile FILE | Memory profiling | go test -memprofile=mem.out -bench=. |
# Exemplo: testes com cobertura em HTML
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out -o coverage.html
Profiling com pprof
Gerar Profiles
# CPU profile
go test -cpuprofile=cpu.out -bench=. ./...
# Memory profile
go test -memprofile=mem.out -bench=. ./...
# Analisar interativamente
go tool pprof cpu.out
# Gerar visualização web
go tool pprof -http=:8080 cpu.out
pprof em Servidor HTTP
package main
import (
"net/http"
_ "net/http/pprof" // registra handlers em /debug/pprof/
)
func main() {
// Seus handlers normais
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("OK"))
})
// pprof disponível em /debug/pprof/
http.ListenAndServe(":8080", nil)
}
| Endpoint pprof | Descrição |
|---|---|
/debug/pprof/ | Índice de profiles |
/debug/pprof/goroutine | Stack traces de goroutines |
/debug/pprof/heap | Alocações de memória |
/debug/pprof/profile | CPU profile (30s por padrão) |
/debug/pprof/trace | Execution trace |
Veja o guia do Flight Recorder e observabilidade com OpenTelemetry para profiling em produção.
Comandos pprof Interativos
| Comando | Descrição |
|---|---|
top | Funções que mais consomem |
top -cum | Top por tempo cumulativo |
list FuncName | Código anotado da função |
web | Gera grafo SVG (requer graphviz) |
png | Gera imagem PNG |
Race Detector
O race detector encontra data races em runtime.
# Testes
go test -race ./...
# Build
go build -race -o app main.go
# Run
go run -race main.go
Quando detecta uma race, imprime:
WARNING: DATA RACE
Read at 0x00c0000b4010 by goroutine 8:
main.main.func2()
/app/main.go:15 +0x30
Previous write at 0x00c0000b4010 by goroutine 7:
main.main.func1()
/app/main.go:11 +0x40
Use Mutex ou channels para resolver. Veja o cheatsheet de concorrência para padrões seguros.
Fuzzing (Go 1.18+)
package math
import "testing"
func FuzzParseInt(f *testing.F) {
// Seed corpus
f.Add("123")
f.Add("-456")
f.Add("0")
f.Add("")
f.Fuzz(func(t *testing.T, input string) {
result, err := ParseInt(input)
if err != nil {
return // erro esperado
}
// Invariante: resultado deve ser >= 0 para inputs positivos
if input[0] != '-' && result < 0 {
t.Errorf("ParseInt(%q) = %d; esperava >= 0", input, result)
}
})
}
# Rodar fuzzing por 30 segundos
go test -fuzz=FuzzParseInt -fuzztime=30s
# Rodar com corpus existente
go test -fuzz=FuzzParseInt
Veja o artigo sobre fuzzing nativo para exemplos avançados.
Testcontainers (Testes de Integração)
Para testes que precisam de banco de dados, cache ou outros serviços, use containers. Veja o guia de Testcontainers.
package db
import (
"context"
"testing"
"github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/modules/postgres"
)
func TestComPostgres(t *testing.T) {
ctx := context.Background()
pg, err := postgres.Run(ctx,
"postgres:16-alpine",
postgres.WithDatabase("testdb"),
)
if err != nil {
t.Fatal(err)
}
defer pg.Terminate(ctx)
connStr, _ := pg.ConnectionString(ctx)
// usar connStr para conectar...
}
Para mais sobre banco de dados, veja Go e PostgreSQL e Go com Docker.
Ferramentas Auxiliares
| Ferramenta | Comando | Descrição |
|---|---|---|
| go vet | go vet ./... | Análise estática |
| staticcheck | staticcheck ./... | Linter avançado |
| golangci-lint | golangci-lint run | Múltiplos linters |
| govulncheck | govulncheck ./... | Vulnerabilidades |
| deadcode | deadcode ./... | Código morto |
| go fmt | gofmt -w . | Formatação |
Veja Melhores Ferramentas Go 2026 e o tutorial de TDD e CI/CD para integrar testes no pipeline. Quer comparar? Veja como Rust integra testes diretamente ao compilador com cargo test, e como Python usa pytest para parametrização e fixtures.
Veja Também
- Cheatsheet: Sintaxe Básica — Variáveis, tipos e funções
- Cheatsheet: Concorrência — Goroutines e race detector
- Cheatsheet: Slices, Maps e Structs — Estruturas de dados
- Cheatsheet: Strings e Formatação — fmt e strconv
- Testes em Go — Tutorial completo de testing
- Performance e Profiling — Guia de otimização
- Erro: Race Condition — Detectar e corrigir data races
- Erro: Deadlock — Resolver deadlocks