使用 go-sqlmock 模拟 gorm `updates` 时无法匹配实际 sql` 错误?
`could not match actual sql` error while mocking gorm `updates` using go-sqlmock?
repository.go
func (repo *Repository) Update(info *model.Requests) error{
if info == nil{
return nil
}
columnChanges := map[string]interface{}{
status: “completed",
}
if err := repo.db.Table(“requests").Model(info).Where(fmt.Sprintf("%s = ? AND %s = ? AND %s = ? AND %s = ?",
requestID, systemID, requestType, status),info.RequestID, info.SystemID, info.RequestType,”progress").Updates(columnChanges).Error; err != nil {
return err
}
return nil
}
模拟
repository_test.go
func TestRepository_Update(t *testing.T) {
type testData struct {
input *model.Requests
queryString string
queryArgs []driver.Value
updateErr error
hasErr bool
}
db, mock, _ := sqlmock.New()
defer db.Close()
dbInstance, _ := gorm.Open("postgres", db)
testDataList := []testData{
{
input: &model.Requests{
RequestID: 4,
SystemID: 2,
RequestType: “mobile",
Status: “completed",
},
queryString: `UPDATE "requests" SET "status" = WHERE (“request_id" = AND “system_id" = AND “request_type" = AND "status" = ) `,
queryArgs: []driver.Value{“completed", 2, 4, “mobile", “progress"},
updateErr: nil,
hasErr: false,
},
}
for _, data := range testDataList {
repo := Repository(zerolog.Nop(), dbInstance)
if data.queryString != "" {
mock.ExpectBegin()
m := mock.ExpectExec(data.queryString).WithArgs(data.queryArgs...)
if data.hasErr {
m.WillReturnError(data.updateErr)
} else {
m.WillReturnResult(sqlmock.NewResult(1, 1))
}
mock.ExpectCommit()
}
resultErr := repo.Requests(data.input)
if data.hasErr {
assert.NotNil(t, resultErr)
} else {
assert.Nil(t, resultErr) //Error thrown in this line
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Errorf("there were unfulfilled expectations: %s", err)
}
}
}
我收到错误
ExecQuery: could not match actual sql: "UPDATE "requests" SET "status" = WHERE (request_id = AND system_id = AND request_type = AND status = )" with expected regexp "UPDATE "requests" SET "status" = WHERE ("request_id" = AND "system_id" = AND "request_type" = AND "status" = )”
Error Trace: repository_test.go:<line number>
Error: Expected nil, but got: &errors.errorString{s:"ExecQuery: could not match actual sql: \"UPDATE \"requests\" SET \"status\" = WHERE (request_id = AND system_id = AND request_type = AND status = )\" with expected regexp \"UPDATE \"requests\" SET \"status\" = WHERE (\”request_id\" = AND \”system_id\" = AND \”request_type\" = AND \"status\" = )\""}
Test: Repository_Update
repository_test.go:<lineNumber>: there were unfulfilled expectations: there is a remaining expectation which was not matched: ExpectedExec => expecting Exec or ExecContext which:
- matches sql: 'UPDATE "requests" SET "status" = WHERE (“request_id" = AND “system_id" = AND “request_type" = AND "status" = ) '
- is with arguments:
0 - success
1 - 2
2 - 4
3 - image
4 - pending
- should return Result having:
LastInsertId: 1
RowsAffected: 1
当我将 gorm 日志级别设置为 true 时,这是我看到的实际 SQL
UPDATE "requests" SET "status" = ‘completed' WHERE (request_id = 5 AND system_id = 1 AND request_type = ‘mobile' AND status = ‘progress')
我试过了,将 ExpectExec
更改为 ExpectPrepare().ExpectExec
或 mock.ExpectQuery(regexp.QuoteMeta
以及其他票证在 go-sqlmock 问题中提到的其他选项。 None 他们成功了。用这个打击了2天。请帮忙。
原因是你没有escaping你的查询字符串的正则表达式。 Sqlmock 期望正则表达式符合您的期望。
现在以防万一你想匹配精确的查询字符串,而不是它的一部分。
您可以指定一个 sqlmock 模拟选项,如下所示:
db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
答案在文档中,如果您阅读 api 文档一次,这可以节省您的时间。
repository.go
func (repo *Repository) Update(info *model.Requests) error{
if info == nil{
return nil
}
columnChanges := map[string]interface{}{
status: “completed",
}
if err := repo.db.Table(“requests").Model(info).Where(fmt.Sprintf("%s = ? AND %s = ? AND %s = ? AND %s = ?",
requestID, systemID, requestType, status),info.RequestID, info.SystemID, info.RequestType,”progress").Updates(columnChanges).Error; err != nil {
return err
}
return nil
}
模拟
repository_test.go
func TestRepository_Update(t *testing.T) {
type testData struct {
input *model.Requests
queryString string
queryArgs []driver.Value
updateErr error
hasErr bool
}
db, mock, _ := sqlmock.New()
defer db.Close()
dbInstance, _ := gorm.Open("postgres", db)
testDataList := []testData{
{
input: &model.Requests{
RequestID: 4,
SystemID: 2,
RequestType: “mobile",
Status: “completed",
},
queryString: `UPDATE "requests" SET "status" = WHERE (“request_id" = AND “system_id" = AND “request_type" = AND "status" = ) `,
queryArgs: []driver.Value{“completed", 2, 4, “mobile", “progress"},
updateErr: nil,
hasErr: false,
},
}
for _, data := range testDataList {
repo := Repository(zerolog.Nop(), dbInstance)
if data.queryString != "" {
mock.ExpectBegin()
m := mock.ExpectExec(data.queryString).WithArgs(data.queryArgs...)
if data.hasErr {
m.WillReturnError(data.updateErr)
} else {
m.WillReturnResult(sqlmock.NewResult(1, 1))
}
mock.ExpectCommit()
}
resultErr := repo.Requests(data.input)
if data.hasErr {
assert.NotNil(t, resultErr)
} else {
assert.Nil(t, resultErr) //Error thrown in this line
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Errorf("there were unfulfilled expectations: %s", err)
}
}
}
我收到错误
ExecQuery: could not match actual sql: "UPDATE "requests" SET "status" = WHERE (request_id = AND system_id = AND request_type = AND status = )" with expected regexp "UPDATE "requests" SET "status" = WHERE ("request_id" = AND "system_id" = AND "request_type" = AND "status" = )”
Error Trace: repository_test.go:<line number>
Error: Expected nil, but got: &errors.errorString{s:"ExecQuery: could not match actual sql: \"UPDATE \"requests\" SET \"status\" = WHERE (request_id = AND system_id = AND request_type = AND status = )\" with expected regexp \"UPDATE \"requests\" SET \"status\" = WHERE (\”request_id\" = AND \”system_id\" = AND \”request_type\" = AND \"status\" = )\""}
Test: Repository_Update
repository_test.go:<lineNumber>: there were unfulfilled expectations: there is a remaining expectation which was not matched: ExpectedExec => expecting Exec or ExecContext which:
- matches sql: 'UPDATE "requests" SET "status" = WHERE (“request_id" = AND “system_id" = AND “request_type" = AND "status" = ) '
- is with arguments:
0 - success
1 - 2
2 - 4
3 - image
4 - pending
- should return Result having:
LastInsertId: 1
RowsAffected: 1
当我将 gorm 日志级别设置为 true 时,这是我看到的实际 SQL
UPDATE "requests" SET "status" = ‘completed' WHERE (request_id = 5 AND system_id = 1 AND request_type = ‘mobile' AND status = ‘progress')
我试过了,将 ExpectExec
更改为 ExpectPrepare().ExpectExec
或 mock.ExpectQuery(regexp.QuoteMeta
以及其他票证在 go-sqlmock 问题中提到的其他选项。 None 他们成功了。用这个打击了2天。请帮忙。
原因是你没有escaping你的查询字符串的正则表达式。 Sqlmock 期望正则表达式符合您的期望。
现在以防万一你想匹配精确的查询字符串,而不是它的一部分。 您可以指定一个 sqlmock 模拟选项,如下所示:
db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
答案在文档中,如果您阅读 api 文档一次,这可以节省您的时间。