dtwupu6414 2014-07-18 10:52
浏览 30
已采纳

测试驱动的开发,以检查涉及数据库查询的方法

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 ?

  • 写回答

2条回答 默认 最新

  • doq70020 2014-07-18 11:36
    关注

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

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥30 win from 窗口最大最小化,控件放大缩小,闪烁问题
  • ¥20 易康econgnition精度验证
  • ¥15 msix packaging tool打包问题
  • ¥28 微信小程序开发页面布局没问题,真机调试的时候页面布局就乱了
  • ¥15 python的qt5界面
  • ¥15 无线电能传输系统MATLAB仿真问题
  • ¥50 如何用脚本实现输入法的热键设置
  • ¥20 我想使用一些网络协议或者部分协议也行,主要想实现类似于traceroute的一定步长内的路由拓扑功能
  • ¥30 深度学习,前后端连接
  • ¥15 孟德尔随机化结果不一致