一个 Go 测试用例中的 DB Mocking 会干扰其他测试用例
DB Mocking in one Go test case is interfering with other test case
我有两个 Go 测试用例,如下所示,用于测试名为 MyEndpoint
.
的 gRPC 函数
MyEndpoint
应该在它选择的数据库行有 Field1 == "A" 时成功,否则 return 会出错。
我正在使用 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
案例中所做的模拟被完全忽略。
如何独立模拟这两个测试用例?
这是因为您在第一次测试中对 modifiedDBRow
切片的分配不正确。请记住,切片不存储任何数据,它只是描述底层数组的一部分。
因此,当您在第一个测试中修改 modifiedDBRow
时,您已经固有地修改了包含 [0]
处值的基础数组,从 A
到 Z
,这当您在下一次测试中阅读 dbRow
时仍然存在。要么在第一个测试结束时重置该值,要么在测试中使用一组不同的变量。
我有两个 Go 测试用例,如下所示,用于测试名为 MyEndpoint
.
MyEndpoint
应该在它选择的数据库行有 Field1 == "A" 时成功,否则 return 会出错。
我正在使用 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
案例中所做的模拟被完全忽略。
如何独立模拟这两个测试用例?
这是因为您在第一次测试中对 modifiedDBRow
切片的分配不正确。请记住,切片不存储任何数据,它只是描述底层数组的一部分。
因此,当您在第一个测试中修改 modifiedDBRow
时,您已经固有地修改了包含 [0]
处值的基础数组,从 A
到 Z
,这当您在下一次测试中阅读 dbRow
时仍然存在。要么在第一个测试结束时重置该值,要么在测试中使用一组不同的变量。