我不确定为什么我的代码省略了select语句接收到的第一行。代码是:
func (s *sqlserver) FindAllProducts() (products []*Product, err error) {
ctx, cancel := getContext()
defer cancel()
rows, err := s.QueryContext(ctx,
"select productid, productname, pricecents, brandname from products")
if err != nil {
return
}
defer rows.Close()
for rows.Next() {
product := new(Product)
err = rows.Scan(
&product.ProductID,
&product.ProductName,
&product.PriceCents,
&product.BrandName,
)
if err != nil {
return
}
products = append(products, product)
}
return
}还有一个单元测试,它使用go-sqlmock来提供测试代码库:
func TestProduct(t *testing.T) {
db, mock, err := sqlmock.New()
if err != nil {
require.NoError(t, err)
}
s := sqlserver{db}
defer s.Close()
product1 := &Product{
1,
"soda",
100,
"prites",
}
product2 := &Product{
60,
"slurpee",
400,
"koce",
}
product3 := &Product{
21,
"borg",
210,
"ham",
}
query := "^insert into *"
mock.ExpectExec(query).
WithArgs(product1.ProductID, product1.ProductName, product1.PriceCents, product1.BrandName).
WillReturnResult(sqlmock.NewResult(0, 1))
query = "^insert into *"
mock.ExpectExec(query).
WithArgs(product2.ProductID, product2.ProductName, product2.PriceCents, product2.BrandName).
WillReturnResult(sqlmock.NewResult(1, 1))
query = "^insert into *"
mock.ExpectExec(query).
WithArgs(product3.ProductID, product3.ProductName, product3.PriceCents, product3.BrandName).
WillReturnResult(sqlmock.NewResult(2, 1))
query = "^select .+ from *"
rows := sqlmock.NewRows([]string{"productid", "productname", "pricecents", "brandname"}).
AddRow(product1.ProductID, product1.ProductName, product1.PriceCents, product1.BrandName)
mock.ExpectQuery(query).
WithArgs(product1.ProductID).
WillReturnRows(rows)
query = "^select .+ from *"
rows.AddRow(product2.ProductID, product2.ProductName, product2.PriceCents, product2.BrandName)
rows.AddRow(product3.ProductID, product3.ProductName, product3.PriceCents, product3.BrandName)
mock.ExpectQuery(query).
WillReturnRows(rows)
err = s.InsertProduct(product1)
assert.NoError(t, err)
err = s.InsertProduct(product2)
assert.NoError(t, err)
err = s.InsertProduct(product3)
assert.NoError(t, err)
product, err := s.FindProductFromID(product1.ProductID)
assert.NoError(t, err)
assert.Equal(t, product1, product)
products, err := s.FindAllProducts()
assert.NoError(t, err)
assert.Len(t, products, 3)
assert.Equal(t, *product1, *products[0])
assert.Equal(t, *product2, *products[1])
assert.Equal(t, *product3, *products[2])
err = mock.ExpectationsWereMet()
assert.NoError(t, err)
}将产品插入到表中可以很好地工作,但是当我尝试使用s.FindAllProducts检索产品时,返回的产品中总是缺少第一个产品(导致assert.Len(t, products, 3)失败)。任何帮助都非常感谢!
编辑:关于在将值扫描到产品中之前调用rows.Next(),这是文档所说的操作,因为指针应该在第一行之前开始一个索引。但是,我已经调试了代码,问题似乎是指针从前面的一个位置开始(指向第一行),然后调用rows.Next()将它移到下一行。我曾尝试在初始化产品后移动此语句,但代码随后抛出错误:Received unexpected error: sql: Scan called without calling Next
编辑2:这似乎是go-sqlmock的一个直接问题,因为在一个真实的SQL数据库上测试之后,数据库正确地返回了所有3行。
发布于 2021-01-02 08:08:21
发现了错误,因为由于某些原因,行是一个指针,go-sqlmock会修改行集,导致其中的原始行被删除,并且每次调用WillReturnRows时都需要重置。代码的以下部分:
query = "^select .+ from *"
rows.AddRow(product2.ProductID, product2.ProductName, product2.PriceCents, product2.BrandName)
rows.AddRow(product3.ProductID, product3.ProductName, product3.PriceCents, product3.BrandName)
mock.ExpectQuery(query).
WillReturnRows(rows)应该修改为添加回原始行,如下所示:
query = "^select .+ from *"
rows = sqlmock.NewRows([]string{"productid", "productname", "pricecents", "brandname"})
rows.AddRow(product1.ProductID, product1.ProductName, product1.PriceCents, product2.BrandName)
rows.AddRow(product2.ProductID, product2.ProductName, product2.PriceCents, product2.BrandName)
rows.AddRow(product3.ProductID, product3.ProductName, product3.PriceCents, product3.BrandName)
mock.ExpectQuery(query).
WillReturnRows(rows)现在测试通过了!
https://stackoverflow.com/questions/65529768
复制相似问题