测试驱动开发,以检查涉及数据库查询的方法 [英] Test driven development to check database queries involved methods

查看:96
本文介绍了测试驱动开发,以检查涉及数据库查询的方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用Golang创建一个数据库驱动的应用程序.我正在尝试以TDD方式进行. 当我尝试测试进行Sql查询的方法时,有哪些可用的软件包?

  • 我不想连接到用于开发的默认数据库.在运行测试时,我可以编写代码来占用另一个测试数据库,但是现在已经有go库了.

  • 是否有任何库可以进行数据库测试而完全不连接数据库?

使用golang进行数据库测试的标准方法是什么?

解决方案

不久前,在重构自己的一些测试时,我也遇到了类似的问题,有几种方法可以做到:

a)提供导出的类型和返回它的OpenConnect函数-例如

 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
}
 

...,然后每个测试,编写设置&拆卸函数,返回您定义数据库函数的*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()中初始化-因为测试没有确定的顺序,因此您需要使用-然后从那里运行测试.即

 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)
   ...
}
 

您可以在 drone.io的GitHub存储库中找到一些实际示例, d还建议有关构建Go应用程序的文章(尤其是数据库方面的内容).

I want to create a database driven application using Golang. I am trying to do it TDD way. When I try to test methods that make Sql queries, What all are the packages available ?

  • I don't want to connect to the default database that I use for development. I can write code to take up another test database while running a test, but is there any go library that already does it.

  • Is there any library that does db tests without connecting to database at all ?

What is the standard way to do database test with golang ?

解决方案

I had a similar question not long ago when refactoring some of my own tests, and there's a couple of ways you can do it:

a) Provide an exported type and an Open or Connect function that returns it - e.g.

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
}

... and then each of your tests, write setup & teardown functions that return an instance of *DB that you define your database functions on (as methods - i.e. 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
}

Note that this is somewhat "integration" testing, but I strongly prefer to test against a "real" database since mocking the interface won't help you catch issues with your queries/query syntax.

b) The alternative, although less extensible on the application side, is to have a global db *sql.DB variable that you initialise in init() within your tests—since tests have no guaranteed order you'll need to use init()—and then run your tests from there. i.e.

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)
   ...
}

You can find some practical examples in drone.io's GitHub repo, and I'd also recommend this article on structuring Go applications (especially the DB stuff).

这篇关于测试驱动开发,以检查涉及数据库查询的方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆