eli*_*rar 15
不久前我在重构我自己的一些测试时遇到了类似的问题,并且有几种方法可以做到:
a)向一个导出的类型和Open或Connect返回它的功能-例如
type DB struct {
db *sql.DB
}
// Using http://jmoiron.github.io/sqlx/ for this example, but
// it has the same interface as database/sql
func Open(opts *Options) (*DB, error) {
db, err := sqlx.Connect(opts.Driver, fmt.Sprintf("host=%s user=%s dbname=%s sslmode=%s", opts.Host, opts.User, opts.Name, opts.SSL))
if err != nil {
return nil, err
}
return &DB{db}, nil
}
Run Code Online (Sandbox Code Playgroud)
...然后你的每个测试,编写设置和拆解函数,返回*DB你定义数据库函数的实例(作为方法 - 即func (db *DB) GetUser(user *User) (bool, error)):
// Setup the test environment.
func setup() (*DB, error) {
err := withTestDB()
if err != nil {
return nil, err
}
// testOptions is a global in this case, but you could easily
// create one per-test
db, err := Open(testOptions)
if err != nil {
return nil, err
}
// Loads our test schema
db.MustLoad()
return db, nil
}
// Create our test database.
func withTestDB() error {
db, err := open()
if err != nil {
return err
}
defer db.Close()
_, err = db.Exec(fmt.Sprintf("CREATE DATABASE %s;", testOptions.Name))
if err != nil {
return err
}
return nil
}
Run Code Online (Sandbox Code Playgroud)
请注意,这是一些"集成"测试,但我更倾向于针对"真实"数据库进行测试,因为模拟界面无法帮助您解决查询/查询语法问题.
b)替代方法虽然在应用程序方面不太可扩展,但是要在测试中db *sql.DB初始化一个全局变量init()- 因为测试没有保证的顺序,你需要使用init()- 然后从那里运行测试.即
var db *sql.DB
func init() {
var err error
// Note the = and *not* the assignment - we don't want to shadow our global
db, err = sqlx.Connect(...)
if err != nil {
...
}
err := db.loadTestSchema
// etc.
}
func TestGetUser(t *testing.T) {
user := User{}
exists, err := db.GetUser(user)
...
}
Run Code Online (Sandbox Code Playgroud)
你可以在drone.io的GitHub repo中找到一些实际的例子,我也推荐这篇关于构造Go应用程序的文章(尤其是DB的东西).