DATA-DOG / go-sqlmock

Sql mock driver for golang to test database interactions
Other
6.05k stars 406 forks source link

Why this sql not match when using postgres? #239

Closed 0xleizhang closed 3 months ago

0xleizhang commented 3 years ago
call to Query 'INSERT INTO "topic" ("name","tags","create_by","score","agree","disagree","create_time","update_time") VALUES ($1,$2,$3,$4,$5,$6,$7,$8) RETURNING "id"' with args [{Name: Ordinal:1 Value:t1} {Name: Ordinal:2 Value:} {Name: Ordinal:3 Value:} {Name: Ordinal:4 Value:0} {Name: Ordinal:5 Value:0} {Name: Ordinal:6 Value:0} {Name: Ordinal:7 Value:2020-10-14 17:47:49} {Name: Ordinal:8 Value:2020-10-14 17:47:49}], was not expected, next expectation is: ExpectedExec => expecting Exec or ExecContext which:
  - matches sql: 'INSERT INTO "topic" ("name","tags","create_by","score","agree","disagree","create_time","update_time") VALUES ($1,$2,$3,$4,$5,$6,$7,$8) RETURNING "id"'
  - is with arguments:
    0 - {}
    1 - {}
    2 - {}
    3 - {}
    4 - {}
    5 - {}
    6 - {}
    7 - {}
  - should return Result having:
      LastInsertId: 15
      RowsAffected: 1
0xleizhang commented 3 years ago
    mock.ExpectExec(`INSERT INTO "topic" ("name","tags","create_by","score","agree","disagree","create_time","update_time") VALUES ($1,$2,$3,$4,$5,$6,$7,$8) RETURNING "id"`).
        WithArgs(sqlmock.AnyArg(),sqlmock.AnyArg(),sqlmock.AnyArg(),sqlmock.AnyArg(),sqlmock.AnyArg(),sqlmock.AnyArg(),sqlmock.AnyArg(),sqlmock.AnyArg()).
        WillReturnResult(sqlmock.NewResult(15, 1))
    mock.ExpectExec(`INSERT INTO "topic"`).
        WillReturnResult(sqlmock.NewResult(15, 1))

this config don't match too

0xleizhang commented 3 years ago

I don't know why this sql can't match!

call to Query 'INSERT INTO "topic" ("name","tags","create_by","score","agree","disagree") VALUES ($1,$2,$3,$4,$5,$6) RETURNING "id"' with args [{Name: Ordinal:1 Value:t1} {Name: Ordinal:2 Value:} {Name: Ordinal:3 Value:} {Name: Ordinal:4 Value:0} {Name: Ordinal:5 Value:0} {Name: Ordinal:6 Value:0}], was not expected, next expectation is: ExpectedExec => expecting Exec or ExecContext which:
  - matches sql: 'INSERT INTO "topic"'
  - is with arguments:
    0 - t1
    1 - 
    2 - 
    3 - 0
    4 - 0
  - should return Result having:
      LastInsertId: 15
      RowsAffected: 1
0xleizhang commented 3 years ago

@file sqlmock_go18.go image

return from here,so not match happened ,Incomprehensible

0xleizhang commented 3 years ago

I understand why not match! because I using xorm,when save will query context first (queryDC) . the next type not match then sqlmock return nil. to fix this,sqlmock can ignore queryContext maybe image

0xleizhang commented 3 years ago

this casuse by xorm using QueryContext for insert when datebase is postgres,mssql,oracle. so when you using mysql this will not happend

0xleizhang commented 3 years ago

注意:使用mysql以上是没问题的 如果你使用的是Postgres或oracle有问题,因为如果是以上数据库xorm是通过QueryContext执行的插入,加上mocksql的Expected类型判断和执行sql什么API绑定的,不是根据SQL解析的。

l3pp4rd commented 3 years ago

Sqlmock is based on a standard sql driver interface. It will not try to adapt to different frameworks, which use it in non standard expected ways. So you can just fork it and customize

Maybe if you are expected exec, instead expect query, this probably will work

cchenggit commented 4 months ago

I have the same problem with xorm, which is blocked me long time. As @seven4x said, xorm implement postgres's insert and returning id by QueryContext, so sqlmock has to used ExpectQuery as expected method. After some test, I found a solution with this situation: using ExpectQuery instead of ExpectExec.

s.SqlMock.ExpectQuery(regexp.QuoteMeta(`INSERT INTO "table" ("id","unique_id","status","create_time","update_time","group_id","user_id") VALUES ($1,$2,$3,$4,$5) RETURNING "id"`)).
                WithArgs(tt.args.po.Id, tt.args.po.UniqueId, tt.args.po.Status, sqlmock.AnyArg(), sqlmock.AnyArg()).
                WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow(1))

            //s.SqlMock.ExpectExec(regexp.QuoteMeta(`INSERT INTO "table" ("id","unique_id","status","create_time","update_time") VALUES ($1,$2,$3,$4,$5) RETURNING "id"`)).
            //  WithArgs(tt.args.po.Id, tt.args.po.UniqueId, tt.args.po.Status, sqlmock.AnyArg(), sqlmock.AnyArg()).
            //  WillReturnResult(
            //      sqlmock.NewResult(1, 1),
            //  )

It will work as same as ExpectExec.


如果有人遇到相同问题, 可以考虑用 ExpectQuery 代替 ExpectExec 执行, 它能得到类似的作用, 并且验证通过。