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
}
Mock
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" = $1 WHERE (“request_id" = $2 AND “system_id" = $3 AND “request_type" = $4 AND "status" = $5) `,
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)
}
}
}
Error I’m getting
ExecQuery: could not match actual sql: "UPDATE "requests" SET "status" = $1 WHERE (request_id = $2 AND system_id = $3 AND request_type = $4 AND status = $5)" with expected regexp "UPDATE "requests" SET "status" = $1 WHERE ("request_id" = $2 AND "system_id" = $3 AND "request_type" = $4 AND "status" = $5)”
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\" = $1 WHERE (request_id = $2 AND system_id = $3 AND request_type = $4 AND status = $5)\" with expected regexp \"UPDATE \"requests\" SET \"status\" = $1 WHERE (\”request_id\" = $2 AND \”system_id\" = $3 AND \”request_type\" = $4 AND \"status\" = $5)\""}
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" = $1 WHERE (“request_id" = $2 AND “system_id" = $3 AND “request_type" = $4 AND "status" = $5) '
- is with arguments:
0 - success
1 - 2
2 - 4
3 - image
4 - pending
- should return Result having:
LastInsertId: 1
RowsAffected: 1
When I set gorm log level true, this is the actual SQL I see
UPDATE "requests" SET "status" = ‘completed' WHERE (request_id = 5 AND system_id = 1 AND request_type = ‘mobile' AND status = ‘progress')
I tried, changing ExpectExec
to ExpectPrepare().ExpectExec
or mock.ExpectQuery(regexp.QuoteMeta
and other options mentioned in go-sqlmock issues by other tickets. None of them worked. Struck with this for 2 days. Please help.
the reason is that you are not escaping your regular expression of query string. Sqlmock expects regular expression in your expectation.
Now in case if you want to match exact query string, not parts of it. You can specify an sqlmock mock option, like this:
db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
The answer was in the documentation, if you would read the api docs once, this could save your time.