Testes em Go: unit, integration, e2e — guia completo

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 é importante?

Go (Golang) é uma linguagem que, desde o seu design, é focada em simplicidade, desempenho e confiabilidade. O pacote embutido testing e ferramentas poderosas, como go test, tornam o processo de escrever testes uma parte essencial do desenvolvimento. Sem testes de qualidade, mesmo o código mais elegante se transforma com o tempo em um sistema "frágil", onde uma única alteração quebra tudo.

Neste artigo, vamos analisar três níveis-chave de teste: unit (unitário), integration (integração) e e2e (end-to-end). Você aprenderá como eles diferem, quando aplicá-los e como escrever testes eficazes em Go. O material será útil tanto para iniciantes quanto para desenvolvedores experientes que desejam sistematizar seus conhecimentos.



1. Teste Unitário

Testes unitários são a base da pirâmide de testes. Eles verificam o funcionamento de funções, métodos ou módulos individuais de forma isolada de dependências externas (banco de dados, rede, sistema de arquivos).



Princípios básicos dos testes unitários em Go

  • Isolamento: O código testado não deve depender de serviços externos.
  • Rapidez: Testes unitários são executados em milissegundos.
  • Determinismo: O resultado do teste não deve mudar de uma execução para outra.


Exemplo de um teste unitário simples

Suponha que temos uma função para somar dois números:

// math.gopackage math

func Add(a, b int) int { return a + b}

O teste para esta função será assim:

// math_test.gopackage math

import "testing"

func TestAdd(t *testing.T) { result := Add(2, 3) expected := 5

if result != expected { t.Errorf("Add(2, 3) = %d; want %d", result, expected) }}

O teste é executado com o comando: go test ./...



Testes orientados a tabela (Table-driven tests)

A comunidade Go prefere testes orientados a tabela para verificar múltiplos casos:

func TestAddTable(t *testing.T) {    tests := []struct {        a, b, expected int    }{        {1, 1, 2},        {0, 0, 0},        {-1, 1, 0},        {100, 200, 300},    }

for _, tt := range tests { result := Add(tt.a, tt.b) if result != tt.expected { t.Errorf("Add(%d, %d) = %d; want %d", tt.a, tt.b, result, tt.expected) } }}

Dica: Use t.Run() para criar testes aninhados com nomes descritivos — isso melhora a legibilidade dos relatórios.



2. Teste de Integração

Testes de integração verificam a interação entre componentes do sistema: banco de dados, API, serviços externos. Ao contrário dos testes unitários, aqui levantamos dependências reais (ou quase reais).



Características dos testes de integração em Go

  • Frequentemente exigem configuração de ambiente (por exemplo, um banco de dados de teste).
  • Podem usar build tags para separar testes unitários e de integração.
  • São executados mais lentamente, por isso são executados separadamente.


Exemplo: testando interação com banco de dados (PostgreSQL)

Criaremos um arquivo com a build tag integration:

// db_test.go//go:build integration

package db

import ( "database/sql" "testing")

func TestSaveUser(t *testing.T) { // Conectando ao banco de dados de teste dsn := "host=localhost user=test password=test dbname=testdb sslmode=disable" db, err := sql.Open("postgres", dsn) if err != nil { t.Fatalf("failed to connect to db: %v", err) } defer db.Close()

// Limpando os dados antes do teste _, _ = db.Exec("TRUNCATE TABLE users")

// Executando a operação sendo testada user := User{Name: "Alice", Email: "alice@example.com"}

Blogs

Book Recommendations