Testes com o pacote testing
1. Introdução ao pacote testing
O pacote testing é a ferramenta nativa do Go para escrever testes unitários, de benchmark e exemplos executáveis. Sua estrutura é minimalista e poderosa, seguindo convenções específicas que facilitam a automação e integração com ferramentas de CI/CD.
Estrutura básica de um teste
Um teste em Go é uma função que começa com Test seguido de um nome com letra maiúscula, recebe um ponteiro para *testing.T e não retorna nada:
package main
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)
}
}
Convenções de nomenclatura
- Arquivos de teste devem terminar com
_test.go(ex:math_test.go) - Testes ficam no mesmo pacote do código testado (teste de caixa branca) ou em pacote separado com
_test(teste de caixa preta) - Funções auxiliares não precisam seguir a nomenclatura
TestXxx
Executando testes com go test
# Executa todos os testes do pacote
go test
# Modo verboso - mostra cada teste executado
go test -v
# Executa apenas testes que correspondem ao padrão
go test -run TestSoma
# Ignora cache e força execução
go test -count=1
2. Asserções e mensagens de erro
O pacote testing não inclui funções de asserção prontas — você escreve condições manualmente. Isso incentiva mensagens de erro descritivas.
t.Error vs t.Fatal
func TestDivisao(t *testing.T) {
// t.Error continua executando após falha
resultado := divisao(10, 2)
if resultado != 5 {
t.Errorf("divisao(10, 2) = %d; esperado 5", resultado)
}
// t.Fatal interrompe o teste imediatamente
_, err := divisao(10, 0)
if err == nil {
t.Fatal("esperava erro de divisão por zero, mas não ocorreu")
}
}
Boas práticas para mensagens descritivas
Sempre inclua os valores reais e esperados na mensagem:
t.Errorf("processarUsuario(%q) = %v; esperado %v", input, resultado, esperado)
Helpers de teste com t.Helper()
Quando você cria funções auxiliares para testes, use t.Helper() para que a linha reportada no erro seja a do teste, não a do helper:
func assertEqual(t *testing.T, got, want interface{}) {
t.Helper()
if got != want {
t.Errorf("got %v, want %v", got, want)
}
}
func TestSoma(t *testing.T) {
assertEqual(t, soma(2, 3), 5) // erro aponta para esta linha
}
3. Testes com subtestes e tabelas
Subtestes com t.Run
Subtestes permitem organizar testes em grupos e executá-los individualmente:
func TestCalculadora(t *testing.T) {
t.Run("Soma", func(t *testing.T) {
if soma(1, 2) != 3 {
t.Error("soma falhou")
}
})
t.Run("Subtracao", func(t *testing.T) {
if subtracao(5, 3) != 2 {
t.Error("subtração falhou")
}
})
}
Execute subtestes específicos com:
go test -run "TestCalculadora/Soma"
Table-driven tests
São casos de teste estruturados em slices de structs, promovendo reutilização e legibilidade:
func TestSoma(t *testing.T) {
testes := []struct {
nome string
a, b int
esperado int
}{
{"números positivos", 2, 3, 5},
{"números negativos", -1, -2, -3},
{"com zero", 0, 5, 5},
}
for _, tt := range testes {
t.Run(tt.nome, func(t *testing.T) {
resultado := soma(tt.a, tt.b)
if resultado != tt.esperado {
t.Errorf("soma(%d, %d) = %d; esperado %d",
tt.a, tt.b, resultado, tt.esperado)
}
})
}
}
Vantagens: fácil adicionar novos casos, cobertura clara, código DRY.
4. Testes de exemplo (Example functions)
Funções ExampleXxx são testes que também geram documentação executável:
func ExampleSoma() {
resultado := soma(2, 3)
fmt.Println(resultado)
// Output: 5
}
O comentário // Output: deve corresponder exatamente à saída padrão. Exemplos aparecem em go doc e são verificados com go test -v.
5. Gerenciamento de estado e limpeza
Setup e teardown com t.Cleanup (Go 1.14+)
Registre funções de limpeza que executam mesmo se o teste falhar:
func TestComBanco(t *testing.T) {
db := setupBanco()
t.Cleanup(func() {
db.Close()
})
// ... testes usando db
}
Testes paralelos com t.Parallel()
Use com cuidado — apenas em testes independentes:
func TestParalelo(t *testing.T) {
t.Parallel()
// teste que não compartilha estado
}
Para resetar variáveis globais entre testes, use funções de setup:
var contador int
func setupTest() {
contador = 0
}
func TestIncremento(t *testing.T) {
setupTest()
incrementa()
if contador != 1 {
t.Errorf("contador = %d; esperado 1", contador)
}
}
6. Testes de benchmark
Funções BenchmarkXxx
Medem desempenho usando o laço b.N que o framework ajusta automaticamente:
func BenchmarkSoma(b *testing.B) {
for i := 0; i < b.N; i++ {
soma(1000, 2000)
}
}
Controle de alocações
func BenchmarkProcessamento(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
processarDados()
}
}
Flags úteis
# Executa benchmarks
go test -bench=.
# Filtra benchmarks por nome
go test -bench=Soma
# Define tempo mínimo por benchmark (default 1s)
go test -bench=. -benchtime=5s
# Número de execuções
go test -bench=. -count=3
7. Cobertura e profiling
Cobertura de código
# Cobertura simples
go test -cover
# Gera arquivo de perfil de cobertura
go test -coverprofile=coverage.out
# Visualização HTML interativa
go tool cover -html=coverage.out
Profiling básico
# CPU profiling
go test -cpuprofile=cpu.out -bench=.
go tool pprof cpu.out
# Memória profiling
go test -memprofile=mem.out -bench=.
go tool pprof mem.out
Com pprof você pode gerar gráficos (SVG, PDF) ou explorar interativamente no terminal.
O pacote testing do Go oferece tudo que você precisa para testes unitários, de desempenho e documentação executável sem dependências externas. A simplicidade das ferramentas incentiva boas práticas como mensagens descritivas, table-driven tests e medição de cobertura — fundamentais para código Go de qualidade.
Referências
- Documentação oficial do pacote testing — Referência completa de tipos, funções e flags do pacote testing
- How to write tests in Go (The Go Blog) — Artigo oficial sobre subtestes e table-driven tests
- Testando código Go (Tutorial Oficial) — Tutorial passo a passo para adicionar testes em Go
- Coverage profiling with Go — Artigo oficial sobre cobertura de código e ferramentas de análise
- Benchmarks in Go (Dave Cheney) — Guia prático de benchmarks com exemplos reais
- pprof documentation — Documentação oficial de profiling com CPU e memória em Go
- Testing Techniques in Go (The Go Dev) — Técnicas avançadas de teste: mocking, interfaces e injeção de dependência