Go语言Docker环境下PostgreSQL集成测试方案咨询
标准Go数据库交互测试方案
针对你的场景,核心思路是解耦数据库依赖 + 用dockertest创建隔离的测试数据库环境,既满足Get函数对指定数据库的依赖,又保证测试的独立性和可重复性。
一、重构代码解耦数据库依赖
当前Get函数直接依赖全局的database.DB,这会导致测试时无法替换为测试用数据库。先做简单重构:
修改 customers.go
import ( "time" "gorm.io/gorm" ) type Customers struct { ID int CustomerName string Active bool Balance float32 ActiveSince time.Time } // 让Get函数接受*gorm.DB参数,不再依赖全局变量 func Get(db *gorm.DB, id int) (Customers, error) { var customer Customers result := db.First(&customer, id) if result.Error != nil { return Customers{}, result.Error } return customer, nil }
(可选)优化 database.go 的灵活性
如果需要在测试中复用连接逻辑,可以新增一个带参数的连接函数:
import ( "fmt" "gorm.io/driver/postgres" "gorm.io/gorm" "os" ) var DB *gorm.DB var err error func Open() error { dsn := fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%s sslmode=disable", os.Getenv("HOST"), os.Getenv("USER"), os.Getenv("PASSWORD"), os.Getenv("DB"), os.Getenv("PORT")) return OpenWithDSN(dsn) } // 新增:通过指定DSN连接数据库,方便测试时传入测试用DSN func OpenWithDSN(dsn string) error { DB, err = gorm.Open(postgres.Open(dsn), &gorm.Config{}) return err } // 新增:获取DB实例的方法,也可以直接用全局变量,但推荐封装 func GetDB() *gorm.DB { return DB }
二、用dockertest搭建测试数据库
dockertest启动新PostgreSQL容器后,你可以在容器内创建指定名称的数据库,再迁移表结构、插入测试数据,完全模拟生产环境的数据库状态。
编写测试文件 customers_test.go
import ( "fmt" "testing" "time" "github.com/ory/dockertest/v3" "github.com/ory/dockertest/v3/docker" "gorm.io/driver/postgres" "gorm.io/gorm" ) func TestGetCustomer(t *testing.T) { // 1. 启动PostgreSQL Docker容器 pool, err := dockertest.NewPool("") if err != nil { t.Fatalf("无法创建dockertest池: %v", err) } resource, err := pool.RunWithOptions(&dockertest.RunOptions{ Repository: "postgres", Tag: "14", Env: []string{ "POSTGRES_PASSWORD=testpass", "POSTGRES_USER=testuser", // 先连接默认postgres库,后续创建业务指定的数据库 "POSTGRES_DB=postgres", }, }, func(config *docker.HostConfig) { config.AutoRemove = true config.RestartPolicy = docker.RestartPolicy{Name: "no"} }) if err != nil { t.Fatalf("无法启动PostgreSQL容器: %v", err) } // 确保容器停止后清理资源 t.Cleanup(func() { if err := pool.Purge(resource); err != nil { t.Logf("无法清理容器: %v", err) } }) // 2. 等待数据库就绪,创建业务指定的数据库 resource.Expire(120) // 2分钟后自动清理容器 var testDB *gorm.DB err = pool.Retry(func() error { // 连接默认postgres库 dsn := fmt.Sprintf("host=localhost user=testuser password=testpass dbname=postgres port=%s sslmode=disable", resource.GetPort("5432/tcp")) db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{}) if err != nil { return err } // 创建你业务中指定的数据库(替换成你的os.Getenv("DB")值,比如"customers_db") if err := db.Exec("CREATE DATABASE customers_db").Error; err != nil { return err } // 连接到刚创建的业务数据库 testDSN := fmt.Sprintf("host=localhost user=testuser password=testpass dbname=customers_db port=%s sslmode=disable", resource.GetPort("5432/tcp")) testDB, err = gorm.Open(postgres.Open(testDSN), &gorm.Config{}) return err }) if err != nil { t.Fatalf("无法连接到测试数据库: %v", err) } // 3. 迁移表结构(和生产环境一致) if err := testDB.AutoMigrate(&Customers{}); err != nil { t.Fatalf("迁移表结构失败: %v", err) } // 4. 插入测试数据 testCustomer := Customers{ CustomerName: "测试用户", Active: true, Balance: 100.5, ActiveSince: time.Now(), } if err := testDB.Create(&testCustomer).Error; err != nil { t.Fatalf("插入测试数据失败: %v", err) } // 5. 测试Get函数 result, err := Get(testDB, int(testCustomer.ID)) if err != nil { t.Fatalf("调用Get函数失败: %v", err) } // 断言结果 if result.CustomerName != testCustomer.CustomerName { t.Errorf("期望用户名: %s, 实际得到: %s", testCustomer.CustomerName, result.CustomerName) } if result.Balance != testCustomer.Balance { t.Errorf("期望余额: %.2f, 实际得到: %.2f", testCustomer.Balance, result.Balance) } }
三、测试运行说明
- 确保本地Docker处于运行状态
- 安装dockertest依赖:
go get github.com/ory/dockertest/v3 - 运行测试:
go test ./... -v
这种方案的优势:
- 完全隔离测试环境,不会污染生产或开发数据库
- 模拟真实的数据库交互,测试结果可靠
- 解耦后的代码更易维护,符合Go的依赖注入思想
内容的提问来源于stack exchange,提问作者mevoker659
相关产品推荐
相关产品推荐

