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

How to mock an update with returning

Open agustin-del-pino opened this issue 1 year ago • 1 comments
trafficstars

Hi!,

I've the following update:

ret := r.db.Exec(regexp.QuoteMeta("UPDATE $1 SET Counter = Counter + $2 RETURNING Counter + 1"), "COUTERS", n)
var c int
ret.Scan(&c)

The test has:

m.ExpectQuery(
		regexp.QuoteMeta(
			`UPDATE $1 SET Counter = Counter + $2 RETURNING Counter + 1`,
		)).WithArgs("COUNTERS", 3).
		WillReturnRows(sqlmock.NewRows([]string{""}).AddRow(1)

When I run the test I got this error.

call to ExecQuery 'UPDATE $1 SET Counter = Counter + $2 RETURNING Counter + 1)' with args [{Name: Ordinal:1 Value:COUNTERS} {Name: Ordinal:2 Value:3}], was not expected, next expectation is: ExpectedQuery => expecting Query, QueryContext or QueryRow which:

  • matches sql: 'UPDATE $1 SET Counter = Counter + $2 RETURNING Counter + 1)'
  • is with arguments: 0 - COUNTERS 1 - 3
  • should return rows: row 0 - [1]

I understand that error is because I'm using Exec. But I don't know how to return the value I need with the Exec mock.

Is there any method for return a value with Exec mock?.

agustin-del-pino avatar Dec 01 '23 11:12 agustin-del-pino

When using ExpecExec(..) it is possible to set expectations for the result by calling .WillReturnResult(..) Have a look at https://github.com/DATA-DOG/go-sqlmock#tests-with-sqlmock for a working example.

IvoGoman avatar Dec 11 '23 16:12 IvoGoman

Hi @agustin-del-pino! It appears you are calling method Exec but expecting a Query instead, which may be your sqlmock issue. But more thoroughly, I think you have a couple of mistakes in your code, some may be due to copy-pasting, but it makes much harder to help you if you don't provide working code (it's fine to redact/change some parts, but make sure at it at least compiles):

  • You are using regexp.QuoteMeta in your call to r.db.Exec (maybe copy-paste error?).
  • r.db.Exec appears to return a single value, which no Exec method in database/sql does (this would give a compilation error). But QueryRow does, and it also returns a *sql.Row that has a Scan method, which none of the returned values of the Exec methods do. Maybe copy-paste error? Otherwise, if you're not using database/sql, please specify which wrapper library and version you are using.
  • You are passing COUTERS in your example code, but in the error you show COUNTERS instead.

To answer the question in the title (How to mock an update with returning): you should either first use Query/QueryRow/QueryContext/QueryRowContext in your runtime code, then your test use the single ExpectQuery method.

diegommm avatar Jun 08 '24 16:06 diegommm