不久前,在重构自己的一些测试时,我也遇到了类似的问题,有两种方法可以做到:
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/sqlfunc 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}…然后进行 每个 测试,编写设置和拆卸函数,这些函数返回
*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}请注意,这有点“集成”测试,但是我强烈希望针对“真实”数据库进行测试,因为模拟接口不会帮助您捕获查询/查询语法的问题。
b)尽管在应用程序方面扩展性较差,但替代方法是在测试中
db*sql.DB初始化一个全局变量,
init()因为测试没有确定的顺序
init(),因此您可以在其中运行该测试。即
var db *sql.DBfunc 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) ...}您可以在drone.io的GitHub
repo中找到一些实际示例,并且我还建议您阅读有关构建Go应用程序(尤其是DB东西)的文章。



