登录
首页 >  Golang >  Go问答

Golang 使用 migrate 和 dockertest

来源:stackoverflow

时间:2024-03-16 23:57:29 361浏览 收藏

在使用 dockertest 进行数据库逻辑测试时,通常会遇到数据库为空的问题,因为 dockertest 创建的临时数据库并未完成迁移。本文提供了一种使用 golang-migrate 库进行数据库迁移的方法。通过在测试设置中提取并应用本地目录中的迁移脚本,可以确保数据库在测试运行前处于所需状态。虽然这种方法可以正常工作,但速度较慢。

问题内容

目标是测试数据库上的逻辑。 dockertest 似乎对此很有用,并且他们提供了如何设置测试的示例。但是,这些临时数据库是空的(未完成迁移)。

使用dockertest时如何迁移数据库?


正确答案


不确定这是最好的方法,但我已经连接了一些示例,并在测试设置中通过 [golang-migrate] lib 提出了完整迁移。

testmain 下面是设置 dockertest 与 postgres db 连接的设置函数。就在运行测试的 m.run() 之前,有 runmigrations 它使用 golang-migrate 提取本地目录中的所有脚本并将它们应用到数据库。它可以工作,但速度相当慢。

func TestMain(m *testing.M) {
    // uses a sensible default on windows (tcp/http) and linux/osx (socket)
    pool, err := dockertest.NewPool("")
    if err != nil {
        log.Fatalf("Could not connect to docker: %s", err)
    }

    // pulls an image, creates a container based on it and runs it
    resource, err := pool.RunWithOptions(&dockertest.RunOptions{
        Repository: "postgres",
        Tag:        "11",
        Env: []string{
            "POSTGRES_PASSWORD=secret",
            "POSTGRES_USER=user_name",
            "POSTGRES_DB=dbname",
            "listen_addresses = '*'",
        },
    }, func(config *docker.HostConfig) {
        // set AutoRemove to true so that stopped container goes away by itself
        config.AutoRemove = true
        config.RestartPolicy = docker.RestartPolicy{Name: "no"}
    })
    if err != nil {
        log.Fatalf("Could not start resource: %s", err)
    }

    hostAndPort := resource.GetHostPort("5432/tcp")
    databaseUrl := fmt.Sprintf("postgres://user_name:secret@%s/dbname?sslmode=disable", hostAndPort)

    log.Println("Connecting to database on url: ", databaseUrl)

    resource.Expire(120) // Tell docker to hard kill the container in 120 seconds

    // exponential backoff-retry, because the application in the container might not be ready to accept connections yet
    pool.MaxWait = 120 * time.Second
    if err = pool.Retry(func() error {
        db, err = sql.Open("postgres", databaseUrl)
        if err != nil {
            return err
        }
        return db.Ping()
    }); err != nil {
        log.Fatalf("Could not connect to docker: %s", err)
    }

    // Migrating DB
    if err := runMigrations("../migrations", db); err != nil {
        log.Fatalf("Could not migrate db: %s", err)
    }

    //Run tests
    code := m.Run()

    // You can't defer this because os.Exit doesn't care for defer
    if err := pool.Purge(resource); err != nil {
        log.Fatalf("Could not purge resource: %s", err)
    }

    os.Exit(code)
}

func runMigrations(migrationsPath string, db *sql.DB) error {
    if migrationsPath == "" {
        return errors.New("missing migrations path")
    }
    driver, err := postgres.WithInstance(db, &postgres.Config{})
    if err != nil {
        return err
    }
    m, err := migrate.NewWithDatabaseInstance("file://"+migrationsPath, "postgres", driver)
    if err != nil {
        return err
    }
    err = m.Up()
    if err != nil && err != migrate.ErrNoChange {
        return err
    }
    return nil
}

终于介绍完啦!小伙伴们,这篇关于《Golang 使用 migrate 和 dockertest》的介绍应该让你收获多多了吧!欢迎大家收藏或分享给更多需要学习的朋友吧~golang学习网公众号也会发布Golang相关知识,快来关注吧!

声明:本文转载于:stackoverflow 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>