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