Pruebas de integración Go con Docker: guía completa
\n\nLas pruebas de integración son una etapa críticamente importante del desarrollo, especialmente en el mundo de los microservicios y sistemas distribuidos. Go (Golang) en combinación con Docker proporciona herramientas potentes y elegantes para crear pruebas de integración confiables. En este artículo, analizaremos cómo configurar el entorno, escribir pruebas para la interacción con bases de datos y servicios externos, utilizando Docker, testcontainers-go y la biblioteca estándar testing.
1. ¿Por qué Docker para pruebas de integración?
\n\nLas pruebas unitarias tradicionales (unit tests) aíslan la lógica, pero no verifican la interacción con dependencias reales: bases de datos, colas, API. Docker resuelve este problema, permitiendo:
\n- \n
- Aislar el entorno: Cada prueba ejecuta un contenedor limpio, eliminando conflictos de estado. \n
- Repetibilidad: Mismo entorno en la máquina local y en CI/CD. \n
- Despliegue rápido: Los contenedores se inician en segundos. \n
- Facilidad de limpieza: Después de la prueba, el contenedor se destruye. \n
Usaremos la biblioteca testcontainers-go — proporciona una API de alto nivel para gestionar el ciclo de vida de los contenedores directamente desde el código de las pruebas.
2. Configuración del proyecto e instalación de dependencias
\n\nCrearemos un servidor HTTP simple en Go que guarda datos en PostgreSQL. Luego escribiremos una prueba de integración que verifique el endpoint.
\n\nEstructura del proyecto:
\nmyapp/\n├── main.go\n├── go.mod\n├── go.sum\n├── handlers/\n│ └── user.go\n└── integration_test.go\n\nPaso 1: Inicializamos el módulo e instalamos testcontainers:
\ngo mod init myapp\ngo get github.com/testcontainers/testcontainers-go\ngo get github.com/testcontainers/testcontainers-go/modules/postgres\ngo get github.com/lib/pq\ngo get github.com/stretchr/testify/assert\n\nPaso 2: Escribimos un manejador simple en handlers/user.go:
package handlers\n\nimport (\n "database/sql"\n "encoding/json"\n "net/http"\n)\n\ntype User struct {\n Name string `json:"name"`\n Age int `json:"age"`\n}\n\nfunc CreateUser(db *sql.DB) http.HandlerFunc {\n return func(w http.ResponseWriter, r *http.Request) {\n var user User\n if err := json.NewDecoder(r.Body).Decode(&user); err != nil {\n http.Error(w, err.Error(), http.StatusBadRequest)\n return\n }\n _, err := db.Exec("INSERT INTO users (name, age) VALUES ($1, $2)", user.Name, user.Age)\n if err != nil {\n http.Error(w, err.Error(), http.StatusInternalServerError)\n return\n }\n w.WriteHeader(http.StatusCreated)\n json.NewEncoder(w).Encode(user)\n }\n}\n\n3. Escribimos la prueba de integración con Docker
\n\nAhora la parte más interesante: la prueba que levanta PostgreSQL en Docker, crea la tabla, inicia nuestro servidor y verifica su funcionamiento.
\n\nArchivo integration_test.go:
package myapp\n\nimport (\n "bytes"\n "context"\n "encoding/json"\n "net/http"\n "net/http/httptest"\n "testing"\n\n "myapp/handlers"\n\n "github.com/lib/pq"\n "github.com/stretchr/testify/assert"\n "github.com/testcontainers/testcontainers-go"\n "github.com/testcontainers/testcontainers-go/modules/postgres"\n "github.com/testcontainers/testcontainers-go/wait"\n)\n\nfunc TestCreateUserIntegration(t *testing.T) {\n ctx := context.Background()\n\n // 1. Iniciamos el contenedor PostgreSQL\n pgContainer, err := postgres.RunContainer(ctx,\n testcontainers.WithImage("postgres:15-alpine"),\n postgres.WithDatabase("testdb"),\n postgres.WithUsername("test"),\n postgres.