【问题标题】:How to test Go code which uses databases(mysql)?如何测试使用数据库(mysql)的 Go 代码?
【发布时间】:2017-12-15 05:18:07
【问题描述】:

我有一个使用 MySQL 的 gRPC 服务,并且需要在每个测试用例之后清除记录。我尝试用事务包装每个测试用例。如果我的 rpc 代码中没有事务,它可以工作,但如果有,则失败。并且会出现如下错误:

can't start transaction
...
sql: Transaction has already been committed or rolled back

然后我尝试使用 truncate 清除记录,但一些测试用例随机失败。

我的代码是这样的(我使用 gorm):

func foo(db *gorm.DB) {
    tx := db.Begin()
    // query and insert
    tx.Commit()
}
// Use transaction to do database cleanup
func TestFooVersion1() {
    testDB := initDB()
    tx = testDB.Begin() // setup
    foo(testDB)
    tx.Rollback() // teardown
}
// Use truncate to do database cleanup
func TestFooVersion2() {
    testDB := initDB()
    foo(testDB)
    truncateTables(testDB) // teardown
}
func truncateTables(db *gorm.DB) {
    // exec "TRUNCATE TABLE table;" for every table
}

使用 DB(MySQL) 测试代码的正确方法是什么? (我不喜欢 go-sqlmock 之类的 mock)

【问题讨论】:

    标签: mysql testing go


    【解决方案1】:

    不看代码很难说,但根据错误,听起来您在多个测试之间共享连接,并且每个测试都在尝试启动事务。确保每个测试都打开自己的连接,启动自己的事务,并在完成后提交或回滚并关闭连接。

    【讨论】:

    • 我添加了一些示例代码。问题是如果我在测试代码中使用事务(如foo 函数),事务将不起作用。
    【解决方案2】:

    也许您可以使用 docker 进行集成测试。直接测试具有活动 mysql 的衍生容器。

    您可以使用来自 testify 的测试套件。 每次测试时,运行 docker 容器,并使用 live mysql 进行测试。

    【讨论】:

    • 我有一个 mysql 用于测试。但它不起作用。顺便说一句,我添加了一些示例代码来解释我的问题。
    • 我明白了。您的解决方案是为每个测试用例启动一个新的 docker 容器。对吗?
    • 是的...它将直接使用实时mysql进行测试
    • 它应该可以工作,但我不确定是否有更好的方法。我试试看。
    • 使用 testify 的测试套件,您可以只为所有测试启动一个容器,无需为每个测试用例启动新测试
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-09-24
    • 2020-03-04
    • 1970-01-01
    • 2020-06-23
    • 2017-11-13
    • 1970-01-01
    • 2016-09-18
    相关资源
    最近更新 更多