多个包单元测试如何编写dockertest?

67 阅读1分钟

多个包进行单元测试时,如何使用dockertest?

  1. 新建单元测试工具包 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,清理失败")
    }
}

  1. 在将要进行单元测试的包内文件内写入:
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容器内数据表操作
}