Integration Testing Go with Docker: Advanced Level

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Integration Testing Go with Docker: Advanced Level



Integration testing is a critically important stage in developing reliable microservices in Go. Isolated unit tests do not guarantee that your application correctly interacts with external dependencies: databases, message queues, caches, and third-party APIs. Docker allows you to spin up real instances of these services in a test environment, ensuring maximum test reliability. In this article, we will explore advanced techniques for integration testing Go applications using Docker.



Why Docker is Important for Integration Tests in Go?

The traditional approach with mocks and stubs only checks the logic of your code, but not the behavior in conjunction with a real DBMS or broker. Docker solves this problem:

  • Environment Reproducibility: tests run in identical conditions locally and in CI/CD.
  • Isolation: each test suite can have its own instance of the service.
  • No "Magic": you are testing exactly the driver/client you use in production.

However, manually managing containers via os/exec or shell scripts quickly becomes unstable. Libraries such as testcontainers-go come to the rescue.



Testcontainers Library for Go: Installation and Basic Example

testcontainers-go is a Go wrapper that programmatically manages the lifecycle of Docker containers. It automatically pulls images, starts, waits for readiness, and cleans up containers after the test.



Installation

go get github.com/testcontainers/testcontainers-gogo get github.com/testcontainers/testcontainers-go/modules/postgres


Basic Example: Testing with PostgreSQL

package integration

import ( "context" "database/sql" "testing" "time"

"github.com/testcontainers/testcontainers-go" "github.com/testcontainers/testcontainers-go/modules/postgres" "github.com/testcontainers/testcontainers-go/wait" _ "github.com/lib/pq")

func TestPostgresConnection(t *testing.T) { ctx := context.Background()

// 1. Start the PostgreSQL container pgContainer, err := postgres.RunContainer(ctx, testcontainers.WithImage("postgres:15"), postgres.WithDatabase("testdb"), postgres.WithUsername("user"), postgres.WithPassword("password"), testcontainers.WithWaitStrategy( wait.ForLog("database system is ready to accept connections"). WithOccurrence(2). WithStartupTimeout(30*time.Second)), ) if err != nil { t.Fatal(err) } defer pgContainer.Terminate(ctx) // Automatic cleanup

// 2. Get the connection string connStr, err := pgContainer.ConnectionString(ctx, "sslmode=disable") if err != nil { t.Fatal(err) }

// 3. Connect and execute a query db, err := sql.Open("postgres", connStr) if err != nil { t.Fatal(err) } defer db.Close()

if err := db.Ping(); err != nil { t.Fatal("Failed to connect to the database:", err) }

// Verify we can create a table and insert data _, err = db.Exec(`CREATE TABLE IF NOT EXISTS users (id SERIAL PRIMARY KEY, name TEXT)`) if err != nil { t.Fatal(err) } t.Log("Integration test with PostgreSQL passed successfully!")}


Advanced Techniques: Parallel Execution and Custom Wait Strategies

When there are many tests, running containers sequentially for each test slows down the execution. We use Go's parallelism and shared containers.



Parallel Tests with a Shared Container

Create one container for the entire package using TestMain:

package integrat                

Blogs

Book Recommendations