Pruebas de integración de Go con Docker: nivel avanzado

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Pruebas de integración de Go con Docker: de la teoría a la práctica avanzada

\n\n

Las pruebas de integración son una etapa crítica en el desarrollo de microservicios en Go. Sin verificar la interacción con bases de datos, colas de mensajes y APIs externas, corres el riesgo de obtener "funciona en mi máquina" en su manifestación más desagradable. Docker permite levantar entornos limpios y aislados para cada prueba, y las técnicas avanzadas permiten hacerlo de forma rápida, paralela y sin dolor. En este artículo, analizaremos enfoques reales utilizados por ingenieros senior.

\n\n

1. Por qué Docker es el socio ideal para las pruebas de integración en Go

\n\n

Go se compila en un binario estático, lo que lo convierte en un candidato ideal para la contenerización. En las pruebas de integración, Docker resuelve tres tareas clave:

\n
    \n
  • Aislamiento: cada prueba obtiene una base de datos o Redis fresca sin "basura" de ejecuciones anteriores.
  • \n
  • Reproducibilidad: las pruebas funcionan igual en la máquina del desarrollador, en CI/CD y en producción.
  • \n
  • Velocidad: los contenedores correctamente configurados se inician en segundos, no en minutos.
  • \n
\n\n

El error principal de los principiantes es ejecutar un solo contenedor para todas las pruebas. Esto provoca condiciones de carrera y errores "intermitentes". El enfoque avanzado: un contenedor por paquete de prueba o incluso por prueba individual.

\n\n

2. Testcontainers para Go: contenedores gestionados desde el código

\n\n

La biblioteca testcontainers-go permite gestionar contenedores Docker directamente desde las pruebas de Go. Esto es más elegante que escribir scripts bash o depender de un Docker Compose previamente ejecutado.

\n\n

Instalación:

\n
go get github.com/testcontainers/testcontainers-go\ngo get github.com/testcontainers/testcontainers-go/modules/postgres
\n\n

Ejemplo: probar PostgreSQL con migraciones:

\n
package integration_test\n\nimport (\n    "context"\n    "database/sql"\n    "testing"\n    "time"\n\n    "github.com/testcontainers/testcontainers-go"\n    "github.com/testcontainers/testcontainers-go/modules/postgres"\n    "github.com/testcontainers/testcontainers-go/wait"\n    _ "github.com/lib/pq"\n)\n\nfunc TestUserRepository(t *testing.T) {\n    ctx := context.Background()\n\n    pgContainer, err := postgres.RunContainer(ctx,\n        testcontainers.WithImage("postgres:16-alpine"),\n        postgres.WithDatabase("testdb"),\n        postgres.WithUsername("user"),\n        postgres.WithPassword("password"),\n        testcontainers.WithWaitStrategy(\n            wait.ForLog("database system is ready to accept connections").\n                WithOccurrence(2).\n                WithStartupTimeout(30*time.Second),\n        ),\n    )\n    if err != nil {\n        t.Fatal(err)\n    }\n    defer pgContainer.Terminate(ctx)\n\n    connStr, err := pgContainer.ConnectionString(ctx, "sslmode=disable")\n    if err != nil {\n        t.Fatal(err)\n    }\n\n    db, err := sql.Open("postgres", connStr)\n    if err != nil {\n        t.Fatal(err)\n    }\n    defer db.Close()\n\n    // Aquí ejecutamos migraciones y pruebas\n    _, err = db.Exec(`CREATE TABLE IF NOT EXISTS users (\n        id SERIAL PRIMARY KEY,\n        name TEXT NOT NULL\n    )`)\n    if err != nil {\n        t.Fatal(err)\n    }\n\n    // Probamos el repositorio\n    repo := NewUserRepository(db)\n    user, err := repo.Create(ctx, "Alice")\n    if err != nil {\n        t.Fatal(err)\n    }\n    if user.Name != "Alice" {\n        t.Errorf("expected Alice, got %s", user.Name)\n    }\n}
\n\n

Puntos clave:

\n
    \n
  • WithWaitStrategy — esperamos hasta que PostgreSQL esté realmente listo, no solo que el contenedor esté iniciado.
  • \n
  • defer pgContainer.Terminate(ctx) — garantiza la limpieza incluso en caso de pánico.
  • \n
  • Cada prueba obtiene su propia instancia de base de datos — aislamiento completo.
  • \n
\n\n

3. Pruebas paralelas y gestión de recursos

\n\n

Go soporta la paralel

Blogs

Book Recommendations