多个包进行单元测试时,如何使用dockertest?
- 新建单元测试工具包 unittest,在包内新建一个名为dockertest.go的文件,内容如下:
package unittest
import (
"fmt"
"github.com/ory/dockertest/v3"
"github.com/ory/dockertest/v3/docker"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"log"
"time"
)
var pool *dockertest.Pool
var resource *dockertest.Resource
var db *gorm.DB
func StartDockerResource() (*dockertest.Pool, *dockertest.Resource, *gorm.DB, error) {
if pool == nil || resource == nil || db == nil {
var err error
pool, err = dockertest.NewPool("")
if err != nil {
return nil, nil, nil, fmt.Errorf("Could not get pool to docker: %s", err)
}
// 启动一个 MariaDB 容器
opts := dockertest.RunOptions{
Repository: "mariadb",
Tag: "latest",
Env: []string{
"MYSQL_ROOT_PASSWORD=root",
"MYSQL_DATABASE=test_db",
},
}
resource, err = pool.RunWithOptions(&opts, func(config *docker.HostConfig) {
config.AutoRemove = true
config.RestartPolicy = docker.RestartPolicy{Name: "no"}
})
if err != nil {
return nil, nil, nil, fmt.Errorf("Could not start resource: %s", err)
}
time.Sleep(5 * time.Second)
// 等待容器启动并准备好接受连接
if err := pool.Retry(func() error {
dbUrl := fmt.Sprintf("root:root@(localhost:%s)/test_db?charset=utf8&parseTime=True&loc=Local&timeout=5s", resource.GetPort("3306/tcp"))
db, err = gorm.Open(mysql.Open(dbUrl), &gorm.Config{})
if err != nil {
return err
}
if s, err := db.DB(); err != nil {
return err
} else {
if err = s.Ping(); err != nil {
return err
}
}
return nil
}); err != nil {
return nil, nil, nil, fmt.Errorf("Could not connect to docker: %s", err)
}
}
return pool, resource, db, nil
}
func CleanupDockerResource() {
if resource != nil {
fmt.Println("准备清理docker资源")
if err := pool.Purge(resource); err != nil {
log.Fatalf("Could not purge resource: %s", err)
}
fmt.Println("完成docker资源清理")
} else {
fmt.Println("docker资源=nil,清理失败")
}
}
- 在将要进行单元测试的包内文件内写入:
var (
db *gorm.DB
)
// 该函数会在其他TestXXX函数运行前先执行。
func TestMain(m *testing.M) {
_, _, db1, err := unittest.StartDockerResource()
if err != nil {
log.Fatalf("Error starting docker resource: %s", err)
}
db = db1
// 自动迁移数据表
db.AutoMigrate(&model.User{})
// 运行测试
code := m.Run()
// 清理资源
unittest.CleanupDockerResource()
os.Exit(code)
}
func TestA(t *testing.T) {
// todo 这里使用db进行dockertest容器内数据表操作
}