简体   繁体   中英

`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
}

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM