go-sqlmock icon indicating copy to clipboard operation
go-sqlmock copied to clipboard

Why this sql not match when using postgres?

Open 0xleizhang opened this issue 4 years ago • 7 comments

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 avatar Oct 14 '20 09:10 0xleizhang

	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 avatar Oct 14 '20 09:10 0xleizhang

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 avatar Oct 14 '20 09:10 0xleizhang

@file sqlmock_go18.go image

return from here,so not match happened ,Incomprehensible

0xleizhang avatar Oct 14 '20 10:10 0xleizhang

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 avatar Oct 14 '20 10:10 0xleizhang

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

0xleizhang avatar Oct 14 '20 10:10 0xleizhang

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

0xleizhang avatar Oct 14 '20 11:10 0xleizhang

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

l3pp4rd avatar Oct 15 '20 16:10 l3pp4rd

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 执行, 它能得到类似的作用, 并且验证通过。

cchenggit avatar Apr 26 '24 12:04 cchenggit