Go与Docker集成测试:完整指南
集成测试是开发中至关重要的阶段,尤其是在微服务和分布式系统领域。Go(Golang)结合Docker为创建可靠的集成测试提供了强大而优雅的工具。本文将讲解如何配置环境、编写与数据库和外部服务交互的测试,使用Docker、testcontainers-go和标准库testing。
1. 为什么选择Docker进行集成测试?
传统的单元测试隔离了逻辑,但无法验证与真实依赖(如数据库、队列、API)的交互。Docker解决了这个问题,它允许:
- 隔离环境:每个测试启动一个干净的容器,避免状态冲突。
- 可重复性:在本地机器和CI/CD中拥有相同的环境。
- 快速部署:容器在几秒内启动。
- 易于清理:测试结束后容器被销毁。
我们将使用testcontainers-go库——它提供了高级API,可直接从测试代码中管理容器的生命周期。
2. 项目配置与依赖安装
我们将创建一个简单的Go HTTP服务器,将数据保存到PostgreSQL中。然后编写一个集成测试来验证端点。
项目结构:
myapp/├── main.go├── go.mod├── go.sum├── handlers/│ └── user.go└── integration_test.go步骤1:初始化模块并安装testcontainers:
go mod init myappgo get github.com/testcontainers/testcontainers-gogo get github.com/testcontainers/testcontainers-go/modules/postgresgo get github.com/lib/pqgo get github.com/stretchr/testify/assert步骤2:在handlers/user.go中编写一个简单的处理器:
package handlers
import ( "database/sql" "encoding/json" "net/http")
type User struct { Name string `json:"name"` Age int `json:"age"`}
func CreateUser(db *sql.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var user User if err := json.NewDecoder(r.Body).Decode(&user); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } _, err := db.Exec("INSERT INTO users (name, age) VALUES ($1, $2)", user.Name, user.Age) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.WriteHeader(http.StatusCreated) json.NewEncoder(w).Encode(user) }}3. 使用Docker编写集成测试
现在是最有趣的部分——测试将在Docker中启动PostgreSQL,创建表,启动我们的服务器并验证其工作。
文件integration_test.go:
package myapp
import ( "bytes" "context" "encoding/json" "net/http" "net/http/httptest" "testing"
"myapp/handlers"
"github.com/lib/pq" "github.com/stretchr/testify/assert" "github.com/testcontainers/testcontainers-go" "github.com/testcontainers/testcontainers-go/modules/postgres" "github.com/testcontainers/testcontainers-go/wait")
func TestCreateUserIntegration(t *testing.T) { ctx := context.Background()
// 1. 启动PostgreSQL容器 pgContainer, err := postgres.RunContainer(ctx, testcontainers.WithImage("postgres:15-alpine"), postgres.WithDatabase("testdb"), postgres.WithUsername("test"), postgres.