英文:
Testing with gorm and sqlmock
问题
我正在努力为我的Go Lambda函数编写一个使用sqlmock和gorm进行测试的测试。
这是我想要测试的函数:
func DoCleanup(con *gorm.DB) {
sixMonthsAgo := time.Now().AddDate(0, -6, 0).Format("2006-02-01")
con.Where("date_to <= ?", sixMonthsAgo).Delete(&Availability{})
con.Where("date_to <= ?", sixMonthsAgo).Delete(&Reservation{})
}
这是我的测试:
func TestDoCleanup(m *testing.T) {
var mock sqlmock.Sqlmock
var db *sql.DB
var err error
db, mock, err = sqlmock.New()
assert.Nil(m, err)
dialector := mysql.New(mysql.Config{
DSN: "sqlmock_db_0",
DriverName: "mysql",
Conn: db,
SkipInitializeWithVersion: true,
})
conn, err := gorm.Open(dialector, &gorm.Config{})
if err != nil {
m.Errorf("Failed to open connection to DB: %v", err)
}
if conn == nil {
m.Error("Failed to open connection to DB: conn is nil")
}
defer db.Close()
mock.ExpectQuery(fmt.Sprintf("DELETE FROM availability WHERE date_to <= '%s'", time.Now().AddDate(0, -6, 0).Format("2006-02-01")))
mock.ExpectQuery(fmt.Sprintf("DELETE FROM reservations WHERE date_to <= '%s'", time.Now().AddDate(0, -6, 0).Format("2006-02-01")))
DoCleanup(conn)
err = mock.ExpectationsWereMet()
assert.Nil(m, err)
}
我不知道我做错了什么。这是我第一次使用sqlmock。我在几个地方阅读了一些资料,我的代码看起来没问题,但是我没有得到结果。我的错误是:
Expected nil, but got: &errors.errorString{s:"there is a remaining expectation which was not matched: ExpectedQuery => expecting Query, QueryContext or QueryRow which:\n - matches sql: 'DELETE FROM availability WHERE date_to <= '2022-13-06''\n - is without arguments"}
有什么想法我做错了什么吗?
英文:
I am struggling with writing a test for my go lambda function with sqlmock and gorm.
This is the function I want to test:
func DoCleanup(con *gorm.DB) {
sixMonthsAgo := time.Now().AddDate(0, -6, 0).Format("2006-02-01")
con.Where("date_to <= ?", sixMonthsAgo).Delete(&Availability{})
con.Where("date_to <= ?", sixMonthsAgo).Delete(&Reservation{})
}
And this is my test:
func TestDoCleanup(m *testing.T) {
var mock sqlmock.Sqlmock
var db *sql.DB
var err error
db, mock, err = sqlmock.New()
assert.Nil(m, err)
dialector := mysql.New(mysql.Config{
DSN: "sqlmock_db_0",
DriverName: "mysql",
Conn: db,
SkipInitializeWithVersion: true,
})
conn, err := gorm.Open(dialector, &gorm.Config{})
if err != nil {
m.Errorf("Failed to open connection to DB: %v", err)
}
if conn == nil {
m.Error("Failed to open connection to DB: conn is nil")
}
defer db.Close()
mock.ExpectQuery(fmt.Sprintf("DELETE FROM availability WHERE date_to <= '%s'", time.Now().AddDate(0, -6, 0).Format("2006-02-01")))
mock.ExpectQuery(fmt.Sprintf("DELETE FROM reservations WHERE date_to <= '%s'", time.Now().AddDate(0, -6, 0).Format("2006-02-01")))
DoCleanup(conn)
err = mock.ExpectationsWereMet()
assert.Nil(m, err)
}
I don't know what I am doing wrong. This is the first time I'm using sqlmock. I've read up a few places, and my code looks fine, but I'm not getting the results. My error is:
Expected nil, but got: &errors.errorString{s:"there is a remaining expectation which was not matched: ExpectedQuery => expecting Query, QueryContext or QueryRow which:\n - matches sql: 'DELETE FROM availability WHERE date_to <= '2022-13-06''\n - is without arguments"}
Any ideas what I'm doing wrong?
答案1
得分: 1
我看到的主要问题是你对查询的期望方式不正确。你应该这样写:
mock.ExpectBegin()
mock.ExpectExec("DELETE FROM `availability` WHERE date_to <= ?").
WithArgs(time.Now().AddDate(0, -6, 0).Format("2006-02-01")).
WillReturnResult(sqlmock.NewResult(0, 0))
mock.ExpectCommit()
这样告诉模拟对象你正在使用一个事务(在删除操作周围使用了ExpectBegin
和ExpectCommit
),查询是带有参数的(使用了WithArgs
),以及查询的返回结果是什么(使用了WillReturnResult
)。
还有一些其他的小改动,比如表名周围的``(MySQL 的习惯用法),以及表名的命名(gorm 通常会将表名转为复数形式,所以要么你在 Availability
上实现了 TableName
方法,要么它会默认为 availabilities
)。
你可以将 DoCleanup
函数改为返回错误,并在测试中查看错误信息,这样可以更好地发现所有这些问题:
func DoCleanup(con *gorm.DB) error {
sixMonthsAgo := time.Now().AddDate(0, -6, 0).Format("2006-02-01")
tx := con.Where("date_to <= ?", sixMonthsAgo).Delete(&Availability{})
if tx.Error != nil {
return tx.Error
}
tx = con.Where("date_to <= ?", sixMonthsAgo).Delete(&Reservation{})
if tx.Error != nil {
return tx.Error
}
return nil
}
...
err = DoCleanup(conn)
assert.Nil(m, err)
...
这样做,并使用当前的代码,你会得到以下错误信息:
Expected nil, but got: &errors.errorString{s:"call to database transaction Begin, was not expected, next expectation is: ExpectedQuery => expecting Query, QueryContext or QueryRow which:\n - matches sql: 'DELETE FROM availability WHERE date_to <= '2022-13-06''\n - is without arguments"}
这告诉你 sqlmock 不希望出现 Begin
,解决了这个问题后,你会得到其他错误信息,这些错误在上面的回答的前半部分中已经解决了。
英文:
the main problem I see is around the way you are expecting the Query to be. Instead of
mock.ExpectQuery(fmt.Sprintf("DELETE FROM availability WHERE date_to <= '%s'", time.Now().AddDate(0, -6, 0).Format("2006-02-01")))
you should have:
mock.ExpectBegin()
mock.ExpectExec("DELETE FROM `availability` WHERE date_to <= ?").
WithArgs(time.Now().AddDate(0, -6, 0).Format("2006-02-01")).
WillReturnResult(sqlmock.NewResult(0, 0))
mock.ExpectCommit()
This will tell the mocking that you are using a transaction (ExpectBegin
and ExpectCommit
around the delete, that the query was made with an argument(WithArgs
), and what the return of the query will be (WillReturnResult
)
There are some other minor changes, like the `` around the table name (a MySQL idiom) and the name of the table (gorm will typically pluralize names so either you implemented TableName
on Availability
or it will default to availabilities).
The best way for you to see all these problems would be to change the DoCleanup
to return errors and then look at them on the test:
func DoCleanup(con *gorm.DB) error {
sixMonthsAgo := time.Now().AddDate(0, -6, 0).Format("2006-02-01")
tx := con.Where("date_to <= ?", sixMonthsAgo).Delete(&Availability{})
if tx.Error != nil {
return tx.Error
}
tx = con.Where("date_to <= ?", sixMonthsAgo).Delete(&Reservation{})
if tx.Error != nil {
return tx.Error
}
return nil
}
...
err = DoCleanup(conn)
assert.Nil(m, err)
...
Doing this, and with the current code you would get
Expected nil, but got: &errors.errorString{s:"call to database transaction Begin, was not expected, next expectation is: ExpectedQuery => expecting Query, QueryContext or QueryRow which:\n - matches sql: 'DELETE FROM availability WHERE date_to <= '2022-13-06''\n - is without arguments"}
This tells you that sqlmock was not expecting a Begin, after solving that you will get the other errors that are resolved in the first part of this answer.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论