Search code examples
gogo-gormgo-sqlmock

gorm different column order and test failure


In my code, I have following model:

type ID uint64

type BaseModel struct {
    ID         ID        `gorm:"column:id;primaryKey;autoIncrement" json:"id"`
    UpdateDate time.Time `gorm:"column:update_date;default:CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" json:"update_date"`
    CreateDate time.Time `gorm:"column:create_date;default:CURRENT_TIMESTAMP" json:"create_date"`
}

type Rollback struct {
    BaseModel
    PID   ID     `gorm:"index"`
    Table       string `gorm:"column:tbl_name"`
    RollbackRow string `gorm:"type:longtext"`
}

I am using CreateInBatches method of gorm.DB struct.

I have unit tests using go-sqlmock. In this model, only insert operations are performed.

func expectRollbackInsert(mock sqlmock.Sqlmock, tablename []string) {
    args := make([]driver.Value, 0)
    for _, val := range tablename {
        args = append(args, 1, val, sqlmock.AnyArg(), sqlmock.AnyArg(), sqlmock.AnyArg())
    }
    mock.ExpectExec(regexp.QuoteMeta("INSERT INTO `rollback` (`payment_id`,`tbl_name`,`rollback_row`,`update_date`,`create_date`) VALUES (?,?,?,?,?)")).
        WithArgs(args...).
        WillReturnResult(sqlmock.NewResult(int64(len(tablename)), int64(len(tablename))))
}

My test cases are failing sometimes due to different order of create_date and update_date.

One such failure is

ExecQuery: could not match actual sql: "INSERT INTO `rollback` (`pid`,`tbl_name`,`rollback_row`,`create_date`,`update_date`) VALUES (?,?,?,?,?),(?,?,?,?,?),(?,?,?,?,?),(?,?,?,?,?),(?,?,?,?,?),(?,?,?,?,?),(?,?,?,?,?),(?,?,?,?,?),(?,?,?,?,?),(?,?,?,?,?),(?,?,?,?,?),(?,?,?,?,?),(?,?,?,?,?),(?,?,?,?,?),(?,?,?,?,?),(?,?,?,?,?),(?,?,?,?,?),(?,?,?,?,?),(?,?,?,?,?),(?,?,?,?,?)" with expected regexp "INSERT INTO `rollback` \(`pid`,`tbl_name`,`rollback_row`,`update_date`,`create_date`\) VALUES \(\?,\?,\?,\?,\?\)"

For my use-case, order of column does not matter in insert. How can I handle it in unit-tests to handle all the scenario?


Solution

  • After reading sqlmock documentation here, I got the following workaround:

    func expectRollbackInsert(mock sqlmock.Sqlmock, tablename []string) {
        args := make([]driver.Value, 0)
        for _, val := range tablename {
            args = append(args, 1, val, sqlmock.AnyArg(), sqlmock.AnyArg(), sqlmock.AnyArg())
        }
        mock.ExpectExec(regexp.QuoteMeta("INSERT INTO `rollback`")).
            WithArgs(args...).
            WillReturnResult(sqlmock.NewResult(int64(len(tablename)), int64(len(tablename))))
    }
    

    I removed columns and values. In my case, I do not need to care about create_date and update_date field, hence it worked fine.