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çãoRegra
Arquivo de teste*_test.go (não é compilado no binário final)
Função de testefunc TestNome(t *testing.T)
Função de benchmarkfunc BenchmarkNome(b *testing.B)
Função de exemplofunc ExampleNome()
TestMainfunc 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étodoDescriçã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étodoDescrição
b.NNú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

FlagDescriçãoExemplo
-vVerbose (mostra t.Log)go test -v ./...
-run REGEXFiltrar testes por nomego test -run TestSoma
-count NRepetir N vezes (desativa cache)go test -count=1 ./...
-raceAtivar race detectorgo test -race ./...
-coverMostrar coberturago test -cover ./...
-coverprofile FILEGerar arquivo de coberturago test -coverprofile=c.out
-bench REGEXRodar benchmarksgo test -bench=. ./...
-benchmemMostrar alocações em benchmarksgo test -bench=. -benchmem
-benchtime DDuração do benchmarkgo test -bench=. -benchtime=5s
-timeout DTimeout por testego test -timeout=30s
-shortHabilita testing.Short()go test -short ./...
-parallel NLimitar testes paralelosgo test -parallel=4
-shuffle onEmbaralhar ordemgo test -shuffle=on
-failfastParar no primeiro errogo test -failfast ./...
-cpuprofile FILECPU profilinggo test -cpuprofile=cpu.out -bench=.
-memprofile FILEMemory profilinggo 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 pprofDescrição
/debug/pprof/Índice de profiles
/debug/pprof/goroutineStack traces de goroutines
/debug/pprof/heapAlocações de memória
/debug/pprof/profileCPU profile (30s por padrão)
/debug/pprof/traceExecution trace

Veja o guia do Flight Recorder e observabilidade com OpenTelemetry para profiling em produção.

Comandos pprof Interativos

ComandoDescrição
topFunções que mais consomem
top -cumTop por tempo cumulativo
list FuncNameCódigo anotado da função
webGera grafo SVG (requer graphviz)
pngGera 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

FerramentaComandoDescrição
go vetgo vet ./...Análise estática
staticcheckstaticcheck ./...Linter avançado
golangci-lintgolangci-lint runMúltiplos linters
govulncheckgovulncheck ./...Vulnerabilidades
deadcodedeadcode ./...Código morto
go fmtgofmt -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