Go:使用数据库初始化运行多个包的测试

huangapple go评论95阅读模式
英文:

Go: Run test from multiple package with DB initialization

问题

我有一个GO项目,具有以下项目结构(每个包中有多个这种文件对)。

- api
    - userHandler.go
    - userHandler_test.go
- database
    - user.go
    - user_test.go

在user.go中,我有User结构体和用于创建/获取/更新用户的函数(我正在使用GORM,但这不是问题所在)。在user_test.go中。

我希望每个不同的文件都能清除数据库(删除所有数据或处于某种状态),所以我尝试为每个文件创建1个suite(使用Testify),然后使用SetupSuite函数,但行为似乎不确定,可能我做错了什么。

所以我的问题是:

  • 有哪种方法可以共享数据库连接?使用全局变量是最好的选择吗?
  • 有哪种方法可以在每个file_test.go运行之前创建数据库表,然后使用自定义数据初始化数据库?

现在我还遇到一个奇怪的错误:运行

go test path/package1
go test path/package2

一切正常,但如果我运行(用于测试所有包)

cd path && go test ./...

我会遇到似乎不确定的错误,这就是为什么我猜测数据库连接没有正确处理的原因。

英文:

I have a GO project with this project structure (multiple couples of this kind of files in each package).

- api
    - userHandler.go
    - userHandler_test.go
- database
    - user.go
    - user_test.go

Inside user.go I have the User struct and the functions to Create/Get/Update a User (I'm using GORM but this is not the issue). In the user_test.go.

I'd like to have the DB cleaned (with all the data removed or in a certain state) for each different file, so I've tried to create 1 suite (using Testify) for each file, then use the SetupSuite function but the behaviour seems not deterministic, and probably I'm doing something wrong.

So my questions are:

  • Which is the best way to have a DB connection shared? Using a global variable is the best option?
  • Which is the best way to create the tables in the DB once and then init the DB with custom data before each file_test.go is run?

Right now I'm also having a strange bug: running

go test path/package1
go test path/package2

Everything works fine, but if I run (for testing all the packages)

cd path && go test ./...

I have errors that seems not to be deterministic, that's why I'm guessing that the DB connection is not handled properly

答案1

得分: 1

如果你的api包依赖于你的database包(看起来是这样的),那么你的api包应该有一种方法来提供一个数据库连接池(比如一个*sql.DB)给它。

在你的api包的测试中,你应该只传入一个初始化的连接池(可能已经预先填充了测试模式/固定数据),然后你可以使用它。这可以是一个在api包的init()函数中初始化的全局变量,或者是每个测试函数中的setup()defer teardown()模式。

下面是前者(最简单)的方法,你只需创建一个共享的数据库和模式供你的测试使用。

package database

import testing

var testDB *sql.DB

// 这个函数在你的实际测试函数之前运行。
func init() {
    var err error
    db, err = sql.Open(...)
    if err != nil {
        log.Fatalf("test init failed: %s", err)
    }

    _, err := db.Exec(`CREATE TABLE ....`)
    if err != nil {
        log.Fatalf("test schema creation failed: %s", err)
    }
}

一些建议:

  • 你也可以调用一个setup()函数来创建一个带有随机后缀的表,并插入你的测试数据,这样你的测试就不会使用相同的测试表(从而冲突或依赖于彼此)。在defer teardown()函数中捕获该表名并删除它。
  • 值得阅读一下这篇文章:https://medium.com/@benbjohnson/structuring-applications-in-go-3b04be4ff091,可以获得一些额外的观点。
英文:

If your api package depends on your database package (which it appears to) then your api package should have a way to provide a database connection pool (e.g. a *sql.DB) to it.

In your tests for the api package, you should just pass in an initialised pool (perhaps with the test schema/fixtures pre-populated) that you can use. This can either be a global you initialise in init() for the api package or a setup() and defer teardown() pattern in each test function.

Here's the former (simplest) approach where you just create a shared database and schema for your tests to use.

package database

import testing

var testDB *sql.DB

// This gets run before your actual test functions do.
func init() {
    var err error
    db, err = sql.Open(...)
    if err != nil {
        log.Fatalf("test init failed: %s", err)
    }

    _, err := db.Exec(`CREATE TABLE ....`)
    if err != nil {
        log.Fatalf("test schema creation failed: %s", err)
    }
}

Some tips:

  • You can also call a setup() function can create a table with a random suffix and insert your test data so that your tests don't use the same test table (and therefore risk conflicting or relying on each other). Capture that table name and dump it in your defer teardown() function.
  • https://medium.com/@benbjohnson/structuring-applications-in-go-3b04be4ff091 is worth reading for some additional perspective.

huangapple
  • 本文由 发表于 2015年6月26日 06:11:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/31061683.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定