Testes em Go: unit, integration, e2e do A ao Z

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução: Por que testar em Go é uma necessidade?

\n

Go (Golang) é uma linguagem de programação moderna, criada para construir sistemas confiáveis e escaláveis. No entanto, mesmo o código mais elegante não está imune a erros. É por isso que os testes são uma parte essencial do desenvolvimento em Go. O pacote embutido testing fornece um conjunto poderoso de ferramentas para escrever testes unitários, testes de integração e até mesmo verificações end-to-end (e2e).

\n

Neste artigo, abordaremos todos os níveis de teste em Go: desde testes unitários simples até cenários e2e complexos. Você aprenderá como estruturar testes corretamente, usar mocks, escrever table-driven tests e configurar testes de integração com dependências reais. O material será útil tanto para iniciantes quanto para desenvolvedores experientes que desejam sistematizar seus conhecimentos.

\n\n

1. Testes unitários em Go: o básico

\n

Testes unitários verificam o funcionamento de funções ou métodos individuais isolados de dependências externas. Em Go, usa-se o pacote padrão testing. As regras principais: os arquivos de teste devem ser nomeados *_test.go, e as funções de teste devem começar com Test.

\n\n

1.1. Teste unitário simples

\n

Vamos considerar uma função de soma de dois números:

\n
// math.go\npackage math\n\nfunc Add(a, b int) int {\n    return a + b\n}
\n

Teste para ela:

\n
// math_test.go\npackage math\n\nimport "testing"\n\nfunc TestAdd(t *testing.T) {\n    result := Add(2, 3)\n    expected := 5\n    if result != expected {\n        t.Errorf("Add(2, 3) = %d; want %d", result, expected)\n    }\n}
\n

Execução dos testes: go test ./... ou go test -v para saída detalhada.

\n\n

1.2. Table-driven tests (testes orientados por tabela)

\n

A comunidade Go usa ativamente a abordagem table-driven para testar vários casos:

\n
func TestAddTableDriven(t *testing.T) {\n    tests := []struct {\n        name string\n        a, b int\n        want int\n    }{\n        {"positive", 2, 3, 5},\n        {"negative", -1, -2, -3},\n        {"zero", 0, 0, 0},\n    }\n    for _, tt := range tests {\n        t.Run(tt.name, func(t *testing.T) {\n            if got := Add(tt.a, tt.b); got != tt.want {\n                t.Errorf("Add() = %d, want %d", got, tt.want)\n            }\n        })\n    }\n}
\n

Essa abordagem torna os testes fáceis de ler e expandir.

\n\n

1.3. Testes com erros

\n

Para funções que retornam erros, use t.Fatal ou t.Errorf:

\n
func TestDivide(t *testing.T) {\n    _, err := Divide(10, 0)\n    if err == nil {\n        t.Fatal("expected error for division by zero")\n    }\n}
\n\n

2. Testes de integração: trabalhando com dependências

\n

Testes de integração verificam a interação entre componentes: banco de dados, API, sistema de arquivos. Em Go, é comum separá-los dos testes unitários usando build tags ou uma estrutura de pacotes separada.

\n\n

2.1. Uso de build tags

\n

Crie um arquivo com a tag //go:build integration no início:

\n
//go:build integration\n\npackage db\n\nimport (\n    "testing"\n    "database/sql"\n    _ "github.com/lib/pq"\n)\n\nfunc TestPostgresConnection(t *testing.T) {\n    dsn := "host=localhost port=5432 user=test password=test dbname=test sslmode=disable"\n    db, err := sql.Open("postgres", dsn)\n    if err != nil {\n        t.Fatalf("failed to open db: %v", err)\n    }\n    defer db.Close()\n    \n    if err := db.Ping(); err != nil {\n        t.Fatalf("failed to ping db: %v", err)\n    }\n}
\n

Execução apenas dos testes de integração: go test -tags=integration ./...

\n\n

2.2. Mocks e stubs

\n

Para isolar testes, use interfaces e mocks. Exemplo com a biblioteca popular gomock:

\n
// user.go\ntype UserRepository interface {\n    GetUser(id int) (*Us                

Blogs

Book Recommendations