Introducción: Por qué las pruebas en Go son la base
Go (Golang) fue creado pensando en la simplicidad y la fiabilidad. El paquete integrado testing es una de las mejores herramientas para escribir pruebas entre los lenguajes modernos. No requiere bibliotecas de terceros para escenarios básicos, pero es fácilmente extensible. En este artículo, analizaremos tres niveles de pruebas: unit, integration y e2e. Aprenderás cómo escribirlas, cuándo aplicarlas y qué herramientas usar. El material será útil tanto para principiantes como para desarrolladores Go experimentados.
1. Pruebas unitarias en Go: la base fundamental
Las pruebas unitarias verifican funciones o métodos individuales de forma aislada. En Go, para ello basta con crear un archivo con el sufijo _test.go y escribir funciones del tipo TestXxx(t *testing.T).
Ejemplo simple de prueba unitaria
Supongamos que tenemos una función de suma:
// math.gopackage main
func Add(a, b int) int { return a + b}Prueba para ella:
// math_test.gopackage main
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) }}Pruebas tabulares (Table-Driven Tests)
La comunidad Go recomienda usar pruebas tabulares para verificar múltiples casos:
func TestAddTable(t *testing.T) { tests := []struct { name string a, b int want int }{ {"positive", 2, 3, 5}, {"negative", -1, -2, -3}, {"zero", 0, 0, 0}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := Add(tt.a, tt.b); got != tt.want { t.Errorf("Add() = %d, want %d", got, tt.want) } }) }}Las pruebas unitarias se ejecutan con el comando:
go test ./...2. Pruebas de integración: verificando la interacción
Las pruebas de integración verifican cómo diferentes partes del sistema funcionan juntas: base de datos, API, sistema de archivos. En Go, es común separarlas en archivos con una etiqueta de compilación o colocarlas en el paquete integration.
Uso de build tags
Crea un archivo integration_test.go con la etiqueta:
//go:build integration
package integration
import ( "database/sql" "testing" _ "github.com/lib/pq")
func TestDatabaseConnection(t *testing.T) { dsn := "host=localhost port=5432 user=test dbname=test sslmode=disable" db, err := sql.Open("postgres", dsn) if err != nil { t.Fatalf("Failed to open DB: %v", err) } defer db.Close()
err = db.Ping() if err != nil { t.Fatalf("Failed to ping DB: %v", err) }}Ejecución solo de las pruebas de integración:
go test -tags=integration ./...Trabajo con la BD de prueba
Para las pruebas de integración, a menudo se usan testcontainers-go o BD en memoria (por ejemplo, SQLite). Ejemplo con testcontainers:
func TestWithPostgresContainer(t *testing.T) { ctx := context.Background() pgContainer, err := postgres.RunContainer(ctx, testcontainers.WithImage("postgres:15"), postgres.WithDatabase("testdb"), ) require.NoError(t, err) defer pgContainer.Terminate(ctx)
dsn, _ := pgContainer.ConnectionString(ctx) // usamos dsn para la conexión}3. Pruebas E2E: verificando el sistema completo
Las pruebas End-to-End simulan el comportamiento del usuario y verifican todo el sistema de principio a fin. En Go, a menudo se escriben para servicios HTTP utilizando el paquete net/http/httptest.
Ejemplo de prueba E2E para una API REST
func TestCreateUserE2E(t *testing.T) { // Se