使用 Docker 进行 Go 集成测试:分步指南

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

Go与Docker集成测试:完整指南



集成测试是开发可靠Go应用程序的关键阶段。与单元测试不同,集成测试检查组件之间的交互:数据库、缓存、外部API。Docker可以隔离测试环境,使测试可重现且独立于主机。在本文中,我们将探讨如何为Go应用程序配置Docker集成测试——从简单容器到使用Testcontainers和CI/CD的高级场景。



1. 为什么在Go集成测试中使用Docker?



Go应用程序通常与PostgreSQL、Redis、MongoDB或其他服务配合使用。在每个开发机器和CI服务器上手动配置这些依赖项是导致错误的途径。Docker解决了这个问题:

  • 可重现性 — 本地和CI环境一致。
  • 隔离性 — 测试不会污染主机系统。
  • 速度 — 容器在几秒内启动。
  • 并行性 — 可以同时运行多个隔离的测试。


考虑一个基本示例:测试一个将数据保存到PostgreSQL的函数。



2. 使用Docker Compose配置测试环境



为测试数据库创建docker-compose.test.yml:



version: '3.8'services:  postgres_test:    image: postgres:16-alpine    environment:      POSTGRES_USER: test      POSTGRES_PASSWORD: test      POSTGRES_DB: testdb    ports:      - "5433:5432"  # 使用非标准端口以避免干扰本地数据库    tmpfs: /var/lib/postgresql/data  # 数据存储在内存中以提升速度


在Go测试中,通过os/exec启动容器或使用testcontainers-go库。我们将展示两种方法。



2.1. 从测试中手动启动Docker Compose



// main_test.gopackage main

import ( "context" "fmt" "os/exec" "testing" "time")

func setupTestDB(t *testing.T) string { t.Helper() // 启动容器 cmd := exec.Command("docker-compose", "-f", "docker-compose.test.yml", "up", "-d") if err := cmd.Run(); err != nil { t.Fatalf("failed to start docker-compose: %v", err) } // 等待PostgreSQL就绪 time.Sleep(3 * time.Second) return "postgres://test:test@localhost:5433/testdb?sslmode=disable"}

func TestSaveUser(t *testing.T) { dsn := setupTestDB(t) db, err := sql.Open("postgres", dsn) if err != nil { t.Fatal(err) } defer db.Close() // ... 测试代码}


缺点:手动sleep,并行测试复杂。最好使用Testcontainers。



2.2. Go的Testcontainers



安装库:

go get github.com/testcontainers/testcontainers-go


自动管理容器的示例:



// repository_test.gopackage repository

import ( "context" "testing" "github.com/testcontainers/testcontainers-go" "github.com/testcontainers/testcontainers-go/wait" "github.com/jackc/pgx/v5/pgxpool")

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

// 请求PostgreSQL容器 req := testcontainers.ContainerRequest{ Image: "postgres:16-alpine", ExposedPorts: []string{"5432/tcp"}, Env: map[string]string{ "POSTGRES_USER": "test", "POSTGRES_PASSWORD": "test", "POSTGRES_DB": "testdb", }, WaitingFor: wait.ForLog("database system is ready to accept connections"), }

postgres, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ ContainerRequest: req

博客

书籍推荐