【问题标题】:DB Mocking in one Go test case is interfering with other test case一个 Go 测试用例中的 DB Mocking 正在干扰其他测试用例
【发布时间】:2021-07-25 16:56:57
【问题描述】:

我有两个 Go 测试用例,如下所示,它们测试一个名为 MyEndpoint 的 gRPC 函数。

MyEndpoint 应该在它选择的数据库行有 Field1 == "A" 时成功,否则返回错误。

我正在使用 go-sqlmock package from Data-dog 模拟数据库。

package mypackage_test

import (
    "github.com/DATA-DOG/go-sqlmock"
    "github.com/stretchr/testify/require"
)


type MyEntity struct {
    Id                     sql.NullInt32 `db:"id"`  
    Field1                 sql.NullString `db:"field1"`
    Field2                 sql.NullString `db:"field2"`
    Field3                 sql.NullString `db:"field3"`
}

var Columns = []string{
    "id",
    "field_1",
    "field_2",
    "field_3"
}



var dbRow = []driver.Value{int32(999), "A", "B", "C"]


func TestMyTestA(t *testing.T) {
    t.Run("Verify MyEndpoint Fails when mocked Database row has Field1 != A", func(t *testing.T) {
        api, err := getMyAPI()
        require.Nil(t, err)
        defer api.Close()

        api.DBMock.ExpectBegin()
        api.DBMock.MatchExpectationsInOrder(false)

        modifiedDBRow := dbRow
        modifiedDBRow[0] = "Z"
        api.DBMock.ExpectQuery("SELECT").
            WithArgs(int32(999)).WillReturnRows(sqlmock.NewRows(Columns).AddRow(modifiedDBRow...))
        api.DBMock.ExpectCommit()
        
        _, err = ... // Call MyEndpoint with parameter Id: int32(999)
        api.DBMock.ExpectClose()
        require.NotNil(t, err)
    })
}

func TestMyTestB(t *testing.T) {
    t.Run("Verify MyEndpoint succeeds when mocked Database row has Field1 == A", func(t *testing.T) {
        api, err := getMyAPI()
        require.Nil(t, err)
        defer api.Close()

        api.DBMock.ExpectBegin()
        api.DBMock.MatchExpectationsInOrder(false)

        api.DBMock.ExpectQuery("SELECT").
            WithArgs(int32(999)).WillReturnRows(sqlmock.NewRows(Columns).AddRow(dbRow...))
        api.DBMock.ExpectCommit()
        
        _, err = ... // Call MyEndpoint with parameter Id: int32(999)
        api.DBMock.ExpectClose()
        require.Nil(t, err)
    })
}

当我单独运行这两个测试用例时,它们都通过了。

但是当我一起运行它们时,TestMyTestB 失败了,因为它认为 Field1 == "Z"。 很明显TestMyTestA 正在干扰TestMyTestB。为什么?

似乎在TestMyTestA 案例中完成的模拟在到达TestMyTestB 时仍然有效,而我在TestMyTestB 案例中所做的模拟被完全忽略了。

如何独立地模拟这两个测试用例?

【问题讨论】:

    标签: go datadog go-sqlmock


    【解决方案1】:

    这是因为在您的第一次测试中对 modifiedDBRow 切片的分配不正确。请记住,切片不存储任何数据,它只是描述底层数组的一部分。

    因此,当您在第一个测试中修改 modifiedDBRow 时,您本质上已将包含值 [0] 的底层数组从 A 修改为 Z,当您在下一个测试。要么在第一次测试结束时重置该值,要么在测试中使用一组不同的变量。

    【讨论】:

    • 谢谢你。那行得通。我做到了:modifiedDBRow := make([]driver.Value, len(dbRow)); copy(modifiedDBRow, dbRow); modifiedDBRow[0] = "Z" 这样,底层数据不变。因此,即使测试用例提前中止,我也不必担心会跳过清理。
    猜你喜欢
    • 1970-01-01
    • 2021-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-07
    • 1970-01-01
    • 2012-07-02
    • 2022-11-27
    相关资源
    最近更新 更多