data-dog / go-sqlmock Goto Github PK
View Code? Open in Web Editor NEWSql mock driver for golang to test database interactions
License: Other
Sql mock driver for golang to test database interactions
License: Other
Is there any way to mock a sql.Rows object?
sqlmock.Rows can not be used as sql.Rows
Hi,
I've been using a lot of go-sqlmock and I'm really liking it. However, there doesn't seem to be way to mock the error returned from rows.Scan() when called on an object returned from database.Query (a rows object). There is an example of how to use RowError to check the error returned from rows.Err(), but this is not the same as the error returned from rows.Scan().
Here I've extended the RowError example from godoc to illustrate my issue:
db, mock, err := New()
if err != nil {
fmt.Println("failed to open sqlmock database:", err)
}
defer db.Close()
rows := NewRows([]string{"id", "title"}).
AddRow(0, "one").
AddRow(1, "two").
RowError(1, fmt.Errorf("row error"))
mock.ExpectQuery("SELECT").WillReturnRows(rows)
rs, _ := db.Query("SELECT")
defer rs.Close()
for rs.Next() {
var id int
var title string
// -------------------------------------------------
// How do we mock this error?
err := rs.Scan(&id, &title)
if err != nil {
fmt.Println("got scan error:", err)
break
}
// -------------------------------------------------
fmt.Println("scanned id:", id, "and title:", title)
}
if rs.Err() != nil {
fmt.Println("got rows error:", rs.Err())
}
I have the following select statement in a GetLinks function:
r.DB.Query("SELECT * FROM links ORDER BY short_url ASC")
And am testing it as follows:
func GetLinksTest(mock sqlmock.Sqlmock, r *repo.Repo, t *testing.T, err error) {
mock.ExpectQuery("SELECT * FROM links ORDER BY short_url ASC").WillReturnRows(link_rows)
if _, err = r.GetLinks(); err != nil {
t.Errorf("error was not expected while selecting from links: %s", err)
}
}
The error that is returned is:
error was not expected while selecting from links: query 'SELECT * FROM links ORDER BY short_url ASC', does not match regex [SELECT * FROM links ORDER BY short_url ASC]
*Note the brackets added around the mock select statement
The most peculiar part of the whole thing is that if I add brackets to my original select statement, they still do not match.
r.DB.Query("[SELECT * FROM links ORDER BY short_url ASC]")
returns
error was not expected while selecting from links: query '[SELECT * FROM links ORDER BY short_url ASC]', does not match regex [SELECT * FROM links ORDER BY short_url ASC]
BUT, if I add brackets to the mock query and not the original query, the test passes!
row, err := r.DB.Query("SELECT * FROM links ORDER BY short_url ASC")
mock.ExpectQuery("[SELECT * FROM links ORDER BY short_url ASC]").WillReturnRows(link_rows)
How is it that brackets are being added to the mock query, and then magically being taken away by adding brackets?
Thanks for an awesome library. I couldn't find a solution to this issue, and hope there's a trivial answer I couldn't reach.
I'm trying to test a function that executes a SELECT
query which will return a row that contains a nondeterministic datum. The nondeterministic datum could be as simple as a timestamp, or as complex as a system process information that was inspected at the moment of INSERT
.
Executing a query without Expect...
is forbidden:
all expectations were already fulfilled, call to query '...' was not expected
The Expect...
series, such as ExpectQuery
, requires a call to WillReturnRows
or WillReturnError
. Otherwise, it seems, it's an error:
query '...' must return a database/sql/driver.rows, but it was not set for expectation
*sqlmock.ExpectedQuery as ExpectedQuery => expecting Query or QueryRow
...
But WillReturnRows
requires a precise row that will be used for an exact matching. The trouble is, I don't know what the precise row would be, because it contains a nondeterministic field.
There is a guide for matching arguments in README.md, but they are used for matching the query - what is to be sent to the database. I need a generous way to match the query result - what is to be received from the database.
Naturally, the solution for arguments doesn't work for matching the query result. The following:
rows := sqlmock.NewRows([]string{
"id", "some_nondeterministic_field"}).
AddRow(1, sqlmock.AnyArg())
mock.ExpectQuery(readQuery).WillReturnRows(rows)
is an error:
sql: Scan error on column index 1: converting driver.Value type sqlmock.anyArgument (\"{}\") to a uint64: invalid syntax
In fact I'd be happy to let sqlmock not do any kind of matching at all. I'd be grateful if I could just execute queries to the db
object, get the result from my function, and do the matching myself.
Any idea?
There is currently a data race when using go-sqlmock in two tests in parallel due to the way the API is currently designed. There is only ever one "mock" database and all operations are done on this. This means two tests cannot use this package in parallel. This is evidenced from the following data race in a package I am developing. I'm going to take a stab and changing the API to accommodate this.
==================
WARNING: DATA RACE
Read by goroutine 10:
github.com/DATA-DOG/go-sqlmock.ExpectQuery()
/Users/jnwhiteh/go/src/github.com/DATA-DOG/go-sqlmock/sqlmock.go:155 +0x138
github.com/jnwhiteh/migration.setupVersioned()
/Users/jnwhiteh/go/src/github.com/jnwhiteh/migration/migration_test.go:35 +0x22a
github.com/jnwhiteh/migration.TestDowngradesUnsupported()
/Users/jnwhiteh/go/src/github.com/jnwhiteh/migration/migration_test.go:61 +0x73
testing.tRunner()
/usr/local/Cellar/go/1.3.3/libexec/src/pkg/testing/testing.go:422 +0x10f
Previous write by goroutine 8:
github.com/DATA-DOG/go-sqlmock.(*conn).Close()
/Users/jnwhiteh/go/src/github.com/DATA-DOG/go-sqlmock/connection.go:24 +0x266
database/sql.(*driverConn).finalClose()
/usr/local/Cellar/go/1.3.3/libexec/src/pkg/database/sql/sql.go:310 +0x175
database/sql.finalCloser.(database/sql.finalClose)·fm()
/usr/local/Cellar/go/1.3.3/libexec/src/pkg/database/sql/sql.go:398 +0x57
database/sql.(*DB).Close()
/usr/local/Cellar/go/1.3.3/libexec/src/pkg/database/sql/sql.go:487 +0x6fa
github.com/jnwhiteh/migration.TestFailingToGetCurrentVersion()
/Users/jnwhiteh/go/src/github.com/jnwhiteh/migration/migration_test.go:54 +0x331
testing.tRunner()
/usr/local/Cellar/go/1.3.3/libexec/src/pkg/testing/testing.go:422 +0x10f
Goroutine 10 (running) created at:
testing.RunTests()
/usr/local/Cellar/go/1.3.3/libexec/src/pkg/testing/testing.go:504 +0xb46
testing.Main()
/usr/local/Cellar/go/1.3.3/libexec/src/pkg/testing/testing.go:435 +0xa2
main.main()
github.com/jnwhiteh/migration/_test/_testmain.go:61 +0xdc
Goroutine 8 (finished) created at:
testing.RunTests()
/usr/local/Cellar/go/1.3.3/libexec/src/pkg/testing/testing.go:504 +0xb46
testing.Main()
/usr/local/Cellar/go/1.3.3/libexec/src/pkg/testing/testing.go:435 +0xa2
main.main()
github.com/jnwhiteh/migration/_test/_testmain.go:61 +0xdc
==================
==================
WARNING: DATA RACE
Write by goroutine 10:
github.com/DATA-DOG/go-sqlmock.ExpectQuery()
/Users/jnwhiteh/go/src/github.com/DATA-DOG/go-sqlmock/sqlmock.go:156 +0x309
github.com/jnwhiteh/migration.setupVersioned()
/Users/jnwhiteh/go/src/github.com/jnwhiteh/migration/migration_test.go:35 +0x22a
github.com/jnwhiteh/migration.TestDowngradesUnsupported()
/Users/jnwhiteh/go/src/github.com/jnwhiteh/migration/migration_test.go:61 +0x73
testing.tRunner()
/usr/local/Cellar/go/1.3.3/libexec/src/pkg/testing/testing.go:422 +0x10f
Previous write by goroutine 8:
github.com/DATA-DOG/go-sqlmock.(*conn).Close()
/Users/jnwhiteh/go/src/github.com/DATA-DOG/go-sqlmock/connection.go:25 +0x2d0
database/sql.(*driverConn).finalClose()
/usr/local/Cellar/go/1.3.3/libexec/src/pkg/database/sql/sql.go:310 +0x175
database/sql.finalCloser.(database/sql.finalClose)·fm()
/usr/local/Cellar/go/1.3.3/libexec/src/pkg/database/sql/sql.go:398 +0x57
database/sql.(*DB).Close()
/usr/local/Cellar/go/1.3.3/libexec/src/pkg/database/sql/sql.go:487 +0x6fa
github.com/jnwhiteh/migration.TestFailingToGetCurrentVersion()
/Users/jnwhiteh/go/src/github.com/jnwhiteh/migration/migration_test.go:54 +0x331
testing.tRunner()
/usr/local/Cellar/go/1.3.3/libexec/src/pkg/testing/testing.go:422 +0x10f
Goroutine 10 (running) created at:
testing.RunTests()
/usr/local/Cellar/go/1.3.3/libexec/src/pkg/testing/testing.go:504 +0xb46
testing.Main()
/usr/local/Cellar/go/1.3.3/libexec/src/pkg/testing/testing.go:435 +0xa2
main.main()
github.com/jnwhiteh/migration/_test/_testmain.go:61 +0xdc
Goroutine 8 (finished) created at:
testing.RunTests()
/usr/local/Cellar/go/1.3.3/libexec/src/pkg/testing/testing.go:504 +0xb46
testing.Main()
/usr/local/Cellar/go/1.3.3/libexec/src/pkg/testing/testing.go:435 +0xa2
main.main()
github.com/jnwhiteh/migration/_test/_testmain.go:61 +0xdc
==================
PASS
Found 2 data race(s)
exit status 66
FAIL github.com/jnwhiteh/migration 1.105s
The following test will pass even if it shouldn't:
func TestSomething(t *testing.T) {
db, err := sql.Open("mock", "")
if err != nil {
t.Fatalf("Could not open mock database: %v", err)
}
sqlmock.ExpectExec("DELETE foo").WillReturnResult(sqlmock.NewResult(1, 1))
if err = db.Close(); err != nil {
t.Fatalf("Could not close database: %v", err)
}
}
If I do something with the database, this will fail as expected:
func TestSomething(t *testing.T) {
db, err := sql.Open("mock", "")
if err != nil {
t.Fatalf("Could not open mock database: %v", err)
}
sqlmock.ExpectExec("DELETE foo").WillReturnResult(sqlmock.NewResult(1, 1))
db.Begin() //db.Exec works as well
if err = db.Close(); err != nil {
t.Fatalf("Could not close database: %v", err)
}
}
Hi everyone!
First, thanks for the excellent work with sqlmock.
I'm writing some test code with the help of go sqlmock.
The following code does not validates if the prepared statement has the correct query.
// main.go
package main
import "database/sql"
func testFunction(db *sql.DB) {
db.Prepare("SELECT")
}
func main() {}
// main_test.go
package main
import (
"testing"
"github.com/stretchr/testify/assert"
sqlmock "gopkg.in/DATA-DOG/go-sqlmock.v1"
)
func TestPrepare(t *testing.T) {
db, mock, mErr := sqlmock.New()
assert.NoError(t, mErr)
defer db.Close()
mock.ExpectPrepare("^BADSELECT$")
testFunction(db)
if err := mock.ExpectationsWereMet(); err != nil {
t.Errorf("there were unfulfilled expections: %s", err)
}
}
As far as i know, the test should fail, but it does't. What i'm i doing wrong?
I'm using GO 1.7/macOS 10.12.1.
Thanks
When declaring ExpectPrepare
for a query with a ?
not at the end of the query, the test will fail, stating that the regex does not match.
Test code:
func TestPrepare() {
sampleQuery := "SELECT * FROM accounts WHERE source = ? LIMIT 100"
db, mock, err := sqlmock.New()
mock.ExpectPrepare(sampleQuery)
db.Prepare(sampleQuery)
}
Error:
query 'SELECT * FROM accounts WHERE source = ? LIMIT 100', does not match regex [SELECT * FROM accounts WHERE source = ? LIMIT 100]
This is, of course, due to the question mark in the sql, but that should be detected when creating the expectation.
By contrast, the following will succeed:
func TestPrepare() {
sampleQuery := "SELECT * FROM accounts WHERE source = ?"
db, mock, err := sqlmock.New()
mock.ExpectPrepare(sampleQuery)
db.Prepare(sampleQuery)
}
Postgresql drivers such as https://github.com/jackc/pgx and https://github.com/go-pg/pg support marshaling and unmarshaling behind the scenes to json as appropriate. Since I am using this feature, it'd be good to be able to test it as well.
What do you think? I'd implement it if it would be merged.
I'm not sure if I'm doing this right but ExpectRollback doesn't trigger in this case :
func TestRollback(t *testing.T) {
db, err := sqlmock.New()
if err != nil {
t.Errorf("an error '%s' was not expected when opening a stub database connection", err)
}
sqlmock.ExpectBegin()
sqlmock.ExpectRollback()
_, errBegin := db.Begin()
if errBegin != nil {
t.Fatal(errBegin)
}
err = db.Close()
if err == nil {
t.Fail()
}
}
I'm hitting an issue where I want to mock a query but I don't know about (or in my particular case; don't care about) some of the arguments that the query was made with. I Also don't know what order the queries are made in
consider this somewhat convoluted example:
https://gist.github.com/nicwest/f902199d47f5c4a7902a
I would like to do something along the lines of
mock.ExpectQuery("SELECT word FROM things").WithUniqueArgs("Fred").WillReturnRows(
sqlmock.NewRows(columns).AddRow("Fish"),
)
mock.ExpectQuery("SELECT word FROM things").WithUniqueArgs("Bat").WillReturnRows(
sqlmock.NewRows(columns).AddRow("Bat"),
)
mock.ExpectQuery("SELECT word FROM things").WithUniqueArgs("Harry").WillReturnRows(
sqlmock.NewRows(columns).AddRow("Horse"),
)
Any suggestions?
We have noticed a false positive problem when asking if the ExpectationsWereMet
with MatchExpectationsInOrder = true
, when expecting Exec
calls against the database.
The problem is not in the order matching, but that outstanding expectations have not been satisfied.
Here is an example. Both the tests in sqlexec_test.go should be failing because RunExecs
second call to Exec
is not expected and as such one of our expected Exec
calls has not been satisfied. The first test, where MatchExpectationsInOrder = true
, is passing - it should not.
Tested on version 3769fed
We think the culprit is that the expectation matched in Exec
has triggered = true
before the query is matched. This currently happens on line 234. Moving this to just above line 251 resolves the issue.
Hey,
How can I mock columns that are stored as datetimes? It seems that RowsFromCSVString
sets driver.Value
s that are always []byte
, and Scan
is unable to parse time.time
objects from them:
Scan error on column index 4: unsupported driver -> Scan pair: []uint8 -> *time.Time
I'd guess this would work if either RowsFromCSVString
was able to directly create time.time
objects when it encounters them or there was another way to assemble sqlmock.rows
objects.
Example:
sqlmock.ExpectQuery("SELECT now()").
WillReturnRows(sqlmock.RowsFromCSVString([]string{"now"}, "2014-02-12 16:04:15.879588-08"))
# sql: Scan error on column index 0: unsupported driver -> Scan pair: []uint8 -> *time.Time
Seems like the install instructions need to be updated:
go get github.com/DATA-DOG/go-sqlmock
Hi,
i am mocking a insert statement but the expectation fails, event though i cannot see why.
The following error message reveal that the arguments are identical.
sql_writer_test.go:29: error was not expected while writing event: exec query 'INSERT INTO Event (SourceId, Created, EventType, Version, Payload) VALUES (?, ?, ?, ?, ?)', args [2eb5880e-4bfd-4450-92fc-df851bae5dbb 2016-02-03 22:05:00.712109 +0000 UTC TEST 1 {"version":1,"name":"Joe","balance":12.99,"birth_date":"2015-12-13T23:59:59+02:00"}] does not match expected [2eb5880e-4bfd-4450-92fc-df851bae5dbb 2016-02-03 22:05:00.712109 +0000 UTC TEST 1 {"version":1,"name":"Joe","balance":12.99,"birth_date":"2015-12-13T23:59:59+02:00"}]
Am i doing something wrong?
Line 352 of expectations.go causes a panic when the driver.Value is a slice of bytes because it is an uncomparable type:
panic: runtime error: comparing uncomparable type []uint8
This panic isn't recovered because it is called directly from sqlmock.Exec. A solution would be to use reflect.DeepEqual instead of using a != check. Another would be to check if either the dargs or the args[k] are slices of bytes and then user bytes.Equal, if not then default to the != check.
My code defines the following query:
const sqlLatestFeed = `select feedid from feed where id = (select max(id) from feed)`
In my mock set up I expect to see this query - note that the same constant is used both in my code and in the mock setup in the unit test.
mock.ExpectQuery(sqlLatestFeed).WillReturnRows(rows)
When I run the test I get the following error.
Error: Expected nil, but got: &errors.errorString{s:"query 'select feedid from feed where id = (select max(id) from feed)', does not match regex [select feedid from feed where id = (select max(id) from feed)]"}
If I substitute another query that does not include a subquery then I do not see the error.
The previous version allowed to simply pass the mock
driver name to the GORM initialiser. Since the new version doesn't expose any interface to set the sql.DB
instance and GORM not doing so either (see this issue) I couldn't figure out a way to test.
Is there a way or do I have to rethink my testing approach?
I'm unable to test the Prepare statement returning an error.
Generating a pull request for an addition of ExpectPrepare(). Made backwards compatible by having Prepare() ignore other expectations when this one not set.
Currently if expected argument is not converted to a supported driver.Value. That means the matching might be not exact or in some cases misleading and requires an user to expect already converted arguments.
Sqlmock should perform the same conversions as sql library for all expected arguments. That will be backward compatible and acting more as expected.
The changes may affect time.Time comparison, since it will be more strict.
The good outcome is that an error message for argument comparison will be more precise and will show exactly which argument did not match.
Hi,
when I started adding tests for one of my db package I had the problem that my queries mostly all contained sub queries (and thus (
and )
) were spread across multiple lines or contained other regex-relevant characters which then were treated by the regex engine which then resulted in lots of exec query 'rawQuery', does not match regex 'rawQuery'
After escaping the first bunch by hand I hacked together this small helper:
// small testing helper to escape `(`, `)` and `$` to not be used as regex modifiers
func escapeQueryToRegex(in string) (out string) {
// replace multiple spaces, tabs and newlines with one space
out = strings.Join(strings.Fields(in), " ")
// slice of regex relevant characters which need to be escaled
chars := []string{`(`, `)`, `$`, `+`}
for _, r := range chars {
out = strings.Replace(out, r, `\`+r, -1)
}
return out
}
I wonder if there is a smarter solution for this problem and if not would have no problem with you guys including this in go-sqlmock. It's an awesome package. Thanks!
Hi,
We have an application that we're using with go-sqlmock, we're receiving a race warning using release d4cd2ca.
Output from go test -race
WARNING: DATA RACE
Write at 0x00c420066e68 by goroutine 32:
domain.example.com/group/project/vendor/gopkg.in/DATA-DOG/go-sqlmock%2ev1.(*sqlmock).ExpectQuery()
/u01/dev/go/src/domain.example.com/group/project/vendor/gopkg.in/DATA-DOG/go-sqlmock.v1/sqlmock.go:373 +0x19e
domain.example.com/group/project.TestprojectManager()
/u01/dev/go/src/domain.example.com/group/project/project_test.go:40 +0xba8
testing.tRunner()
/usr/local/go/src/testing/testing.go:610 +0xc9
Previous read at 0x00c420066e68 by goroutine 34:
domain.example.com/group/project/vendor/gopkg.in/DATA-DOG/go-sqlmock%2ev1.(*sqlmock).Query()
/u01/dev/go/src/domain.example.com/group/project/vendor/gopkg.in/DATA-DOG/go-sqlmock.v1/sqlmock.go:341 +0xaa5
database/sql.(*DB).queryConn()
/usr/local/go/src/database/sql/sql.go:1092 +0x68b
database/sql.(*DB).query()
/usr/local/go/src/database/sql/sql.go:1079 +0x188
database/sql.(*DB).Query()
/usr/local/go/src/database/sql/sql.go:1062 +0xad
database/sql.(*DB).QueryRow()
/usr/local/go/src/database/sql/sql.go:1143 +0x80
domain.example.com/group/project.(*channel).poll()
/u01/dev/go/src/domain.example.com/group/project/channel.go:84 +0x2e8
domain.example.com/group/project.(*channel).poller()
/u01/dev/go/src/domain.example.com/group/project/channel.go:58 +0x9e
Goroutine 32 (running) created at:
testing.(*T).Run()
/usr/local/go/src/testing/testing.go:646 +0x52f
testing.RunTests.func1()
/usr/local/go/src/testing/testing.go:793 +0xb9
testing.tRunner()
/usr/local/go/src/testing/testing.go:610 +0xc9
testing.RunTests()
/usr/local/go/src/testing/testing.go:799 +0x4ba
testing.(*M).Run()
/usr/local/go/src/testing/testing.go:743 +0x12f
main.main()
domain.example.com/group/project/_test/_testmain.go:78 +0x1b8
Goroutine 34 (running) created at:
domain.example.com/group/project.newChannel()
/u01/dev/go/src/domain.example.com/group/project/channel.go:40 +0x1e0
domain.example.com/group/project.(*projectManager).add()
/u01/dev/go/src/domain.example.com/group/project/project.go:37 +0xca
domain.example.com/group/project.(*projectManager).pollDB()
/u01/dev/go/src/domain.example.com/group/project/project.go:87 +0x684
domain.example.com/group/project.NewprojectManager()
/u01/dev/go/src/domain.example.com/group/project/project.go:28 +0x11f
domain.example.com/group/project.TestprojectManager()
/u01/dev/go/src/domain.example.com/group/project/project_test.go:26 +0x70c
testing.tRunner()
/usr/local/go/src/testing/testing.go:610 +0xc9
Essentially:
mock.ExpectQuery(....)
I'm raising this issue as the README states supports concurrency and multiple connections
and I can't easily work around this (having all Expect* calls before Goroutine 34 would be executed) without greatly limiting the effectiveness of the test.
Any thoughts, it appears the c.expected
may need to be guarded as well?
I'm trying to add a test that expects no queries to occur. I imagined this would be simply creating a mock db and it would raise an error if an unexpected query of some kind happened. It looks like it does, but it doesn't fail the test.
all expectations were already fulfilled, call to query 'SELECT store_id, address, topic FROM webhook WHERE id=0 AND active=1 LIMIT 1;' with args [] was not expected
PASS
ok github.com/foo 0.011s
I'm assuming this would be something that needs to go in here to compare the count?
Line 146 in d4cd2ca
My function calls QueryRow, in the test I've set up an ExpectQuery as if it were a normal Query. The QueryRow does not appear to satisfy the expectation. Is that expected?
Any function that calls rows.Close()
causes a sql: duplicate driverConn close
when calling db.Close()
on the mock db object.
Sample code for illustration purposes
Sample function:
type MyDatabase struct {
sql.DB
}
func (db *MyDatabase) GetThing(thing string) (data []byte, err error) {
stmt := "SELECT ..."
rows, err := db.Query(stmt, thing)
if err != nil {
return nil, err
}
defer rows.Close()
...
}
Sample test:
func TestMySQLGetTimestampKeyNoKey(t *testing.T) {
db, _ := sqlmock.New()
s := MyDatabase{DB: db}
sqlmock.ExpectQuery(
"SELECT `cipher`, `public` FROM `timestamp_keys` WHERE `gun`=\\?;",
).WithArgs("testGUN").WillReturnError(sql.ErrNoRows)
foo, err = s.GetThing("testThing")
...
err = db.Close()
assert.Nil(t, err, "Expectation not met: %v", err)
}
Commenting out that defer rows.Close()
stops the error being raised. I don't see anything in the go-sqlmock code that would make this happen and I don't have time to dig into it right now.
After many ExpectQuery tests, I copy-pasted it for an exec. The error made it seem like the arguments were mismatched when in reality I needed ExpectExec.
Please clean-up this error so that when the queries match that it indicates it should have been an Exec.
When I set WillReturnCloseError on ExpectPrepare, the driver.Stmt returned for the associated Prepare doesn't return an error when I try to close it.
See example code here:
https://github.com/iangudger/sqlmock_prepare_example/blob/master/main.go
I'm trying to test a method that is first updating a row using its ID and then reading the updated row using its ID:
_, err := DB.Exec("UPDATE baskets SET property = ? WHERE id = ?", prop, id)
err = DB.Get(basket, "SELECT id, property, created_at, updated_at FROM baskets WHERE id = ?", id)
For mocking in the unit tests, I have:
rows = sqlmock.NewRows([]string{"id", "property", "created_at", "updated_at"}).AddRow(id, oldProp, timeNow, timeNow)
mock.ExpectExec("UPDATE baskets").WithArgs(newProp, id).WillReturnResult(sqlmock.NewResult(0, 1))
mock.ExpectQuery("^SELECT (.+) FROM baskets WHERE").WithArgs(id).WillReturnRows(rows)
The second ExpectQuery obviously fails because the oldProp is updated to newProp. So how can I test my function by mocking row update and then running a select query?
N.B. I'm using sqlx methods above, which seem to work fine with go-sqlmock lib.
It'd be nice if the mock rows struct would expect Close() to be called, either by default or with an ExpectClose() enabler. Most of the time the closing is deferred, but we want to test that it happens.
suppose I've made mistake on writing the query on both of the mock and the real query for insert data. For example :
mock.ExpectExec("INSER INTO table").WithArgs("2017-12-21", 1234).WillReturnResult(sqlmock.NewResult(1, 1))
and the query sintax :
buff := bytes.NewBufferString(`
INSER INTO table(
date,
shop_id
) VALUES ($1, $2)
`)
query := txShop.Rebind(buff.String())
_, err = txShop.Exec(query, Date, shopIdInt)
Notice that I wrote the wrong sintax on INSER
it should be INSERT
. is there any way to add new checking algorithm of sintax query?
I think it would be useful to allow the option of expectations to be reused by adding a flag similar to MatchExpectationsInOrder
defaulting to false. When set it would add a bypass to the continue
in the if next.fulfilled() { ... }
blocks.
Is it possible to disable or limit that expectations were met? I'm happy just to have a db mock which allows my transactional code to be unit tested. Is there another way I should be doing this?
Hi ,
The following test will fail:
package main
import (
"database/sql"
"fmt"
)
func testFunction(db *sql.DB) {
stmt, err := db.Prepare("SELECT id FROM test WHERE id=$1")
if err != nil {
fmt.Println(err)
}
stmt.QueryRow("2")
stmt.Close()
}
func main() {}
package main
import (
"testing"
"github.com/stretchr/testify/assert"
sqlmock "gopkg.in/DATA-DOG/go-sqlmock.v1"
)
func TestPrepare(t *testing.T) {
db, mock, mErr := sqlmock.New()
assert.NoError(t, mErr)
defer db.Close()
mock.ExpectPrepare("^SELECT id FROM test WHERE id=\\$1$")
mock.ExpectQuery("2")
testFunction(db)
if err := mock.ExpectationsWereMet(); err != nil {
t.Errorf("there were unfulfilled expections: %s", err)
}
}
If i replace the code with
mock.ExpectQuery("1")
and
stmt.QueryRow("1")
everything runs as expected.
I'm i doing something wrong?
Thanks
Hey,
I was wondering if it would be beneficial to add AnyTime
to the library so that I don't need to define it in my test code.
I would also wonder if a AnyString
would be useful. I had to create something like that to handle mocking the creation of a User model with a password that need to be encrypted via bcrypt before storing into the database. AnyString is useful because bcrypt doesn't always output the same thing every time and makes matching troublesome.
Thanks again for this library!
How does this method affect expectation matching? There could be two ways it could work:
Which of the above (or some other logic) is the current functionality? The documentation seems to have skipped over this.
I believe this commit changed the argument type of WillReturnRows from Rows
to *Rows
, which broke a lot of my existing test code. Perhaps a note in the README would help others in the same situation.
Hi, as stated in the title, I am having an issue testing an api endpoint with ExpectQuery. I am using the 'Gin' framework.
This is not working as expected:
mock.ExpectQuery("^SELECT (.+) FROM user where id=? LIMIT 1$").WithArgs(1).WillReturnRows(rows)
it's failing and returning:
query 'SELECT * FROM user WHERE id=? LIMIT 1', does not match regex [^SELECT (.+) FROM user where id=? LIMIT 1$]
I have created a gist here which reproduces the issue. https://gist.github.com/dvwright/490ed14a72ae7dab818026b1081f689c
The 'TestGetUsers' test passes, the 'TestGetSpecificUser' test does not pass.
I am new to golang so please feel free to point out user error, or another way to accomplish my goal.
Thanks
This is probably something silly, but I could't find a similar problem.
I have a query that must return the inserted id
:
INSERT INTO AuctionUser (name, coins) VALUES ($1, $2) RETURNING id;
I'm using lib/pq
, and it doesn't support the LastInsertId method.
Anyway, my test is failing at the point on which I decide the returning rows:
mock.ExpectQuery("INSERT INTO AuctionUser (.+) RETURNING id").
WithArgs(mockUser.Name, mockUser.Coins).
WillReturnRows(sqlmock.NewRows([]string{"id"}))
It says that it has no rows on result set
.
Am I missing something?
The new Rows
struct is not backward compatible with the previous Rows
interface; it's missing all of the driver.Rows
methods. T
he changelog and commit message from #68 leads one to believe that was an inadvertent change.
I have a test that mocks 2 subsequent DB queries. After an upgrade to 1.8.1 Go version the second mock fails to return the data every other time. On 1.7.4_2 it was working consistently with no issues.
Here are my 2 mocks:
mock.ExpectQuery("^SELECT (.+) COALESCE(.+)$").WillReturnRows(rows)
mock.ExpectQuery("^SELECT count(.+)$").WillReturnRows(rowsForTotal)
func TestLogHistory(t *testing.T) {
var mock sqlmock.Sqlmock
var err error
db, mock, err = sqlmock.New()
if err != nil {
t.Fatal(err)
}
mock.ExpectPrepare("INSERT INTO").ExpectExec().WithArgs("2")
stmt, err := db.Prepare("INSERT INTO history VALUES(?)")
if err != nil {
panic(err)
}
if _, err := stmt.Exec("2"); err != nil {
t.Fatal(err)
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Fatal(err)
}
}
--- FAIL: TestLogHistory (0.00s)
db_test.go:33: exec query 'INSERT INTO history VALUES(?)' with args [2], must return a database/sql/driver.result, but it was not set for expectation *sqlmock.ExpectedExec as ExpectedExec => expecting Exec which:
- matches sql: 'INSERT INTO'
- is with arguments:
0 - 2
I can't figure out how to setup the mock to expect an insert. Any tips ?
For instance, maybe you are trying to find a user based on their email address, if the query comes back with 0 rows in real life, you know that the user doesn't exist. There should be a way to return 0 rows without throwing an error.
I have functions that do multiple calls to ExpectedQuery
in order to test the behavior of some of my functions that use those queries in that order. Something like this:
func mockFunc1(mock sqlmock.Sqlmock) {
query1 := "..."
query1Rows := sqlmock.NewRows([]string{"column1, column2"}).FromCSVString("value1, value2")
mock.ExpectQuery(query1).WillReturnRows(query1Rows)
query2 := "..."
query2Rows := sqlmock.NewRows([]string{"column1"}).FromCSVString("value1")
mock.ExpectQuery(query2).WillReturnRows(query2Rows)
}
func mockFunc2(mock sqlmock.Sqlmock) {
query3 := "..."
query3Rows := sqlmock.NewRows([]string{"column1"}).FromCSVString("value1")
mock.ExpectQuery(query3).WillReturnRows(query3Rows)
}
Then I have the function that I want to test:
func myFunc(){
callToQuery1()
callToQuery2()
}
And finally, that is what I do on my test function:
func myFunctionTest(t *testing.T){
Db_driver, mock, err := sqlmock.New()
if err != nil {
t.Log("Error on DB mock creation: ", err)
}
defer Db_driver.Close()
mock.MatchExpectationsInOrder(true)
mockFunc1(mock)
mockFunc2(mock)
myFunc()
callToQuery3()
err = mock.ExpectationsWereMet()
if err != nil {
t.Log(err, " expectations not met")
}
}
What happens here is that if I call first mockFunc1(mock)
and then mockFunc2(mock)
the test will fail saying that "query3 does not match regex for query1", but if I call first mockFunc2(mock)
and then mockFunc1(mock)
all goes nicely and the test pass.
I inspected all the values that I retrieved from the mock when issuing the calls and the values are correct, but mock.ExpectationsWereMet()
will say that "query1 expectation not met", which cannot be, since I got the values retrieved from that query.
So these are my two doubts. First, I don't know what I have to call the mockFuncs in reverse order (which I'm 100% sure that the queries in my code are executed in the order query1, query2, query3), and the second question is what ExpectationsWereMet
states that query1 expectation was not met when it actually was (I also checked that every regex I stated is matching my queries). Thanks in advance.
LastInsertId always passes back the int64 in the mocked result. Can't quite get to 100% code coverage without forcing a LastInsertId error.
func (r *result) LastInsertId() (int64, error) {
return r.insertID, nil
}
https://github.com/DATA-DOG/go-sqlmock/blob/master/result.go#L25
In my code:
_, err = db.Exec("INSERT INTO mytable(a, b) VALUES(?,?)
and in my test:
sqlmock.ExpectExec("INSERT INTO mytable(a,b)")
.WithArgs("A", "B")
....
But I get the message:
INSERT INTO mytable(a, b) VALUES(?,?) does not match regex INSERT INTO mytable(a,b)
I've tried adding the values to the expectation parameters and escaping the question marks but with no joy. Is this possible?
It would be nice if the docs mentioned this.
This library is very useful, btw.
I would like to force errors in other places such as:
http://golang.org/pkg/database/sql/#Rows.Scan
http://golang.org/pkg/database/sql/#Rows.Columns
Are there any plans about this?
Create statement is attempting Regex for some reason, and is not matching on the same value I put in the Exec
as I do in the ExpectedExec
.
Error message:
Installation failed for MySQL adapater. exec query 'CREATE TABLE IF NOT EXISTS credential ( credential_id INT(10) NOT NULL AUTO_INCREMENT, username VARCHAR(255) NOT NULL, password TEXT NOT NULL, created_at DATETIME NOT NULL, PRIMARY KEY (credential_id), UNIQUE INDEX username_lookups (username ASC));', does not match regex 'CREATE TABLE IF NOT EXISTS credential ( credential_id INT(10) NOT NULL AUTO_INCREMENT, username VARCHAR(255) NOT NULL, password TEXT NOT NULL, created_at DATETIME NOT NULL, PRIMARY KEY (credential_id), UNIQUE INDEX username_lookups (username ASC));'
Example code:
const (
installSQL = `CREATE TABLE IF NOT EXISTS credential (
credential_id INT(10) NOT NULL AUTO_INCREMENT,
username VARCHAR(255) NOT NULL,
password TEXT NOT NULL,
created_at DATETIME NOT NULL,
PRIMARY KEY (credential_id),
UNIQUE INDEX username_lookups (username ASC));`
)
func runInstallSQL(db *sql.DB) error {
_, err := db.Exec(installSQL)
return err
}
Example test:
func Test_runInstallSQL(t *testing.T) {
db, mock, err := sqlmock.New()
if err != nil {
t.Fatalf("cannot start mock sql for testing: %s", err)
}
defer db.Close()
mock.ExpectExec(installSQL).WillReturnError(nil)
assert.Nil(t, runInstallSQL(db))
assert.Nil(t, mock.ExpectationsWereMet(), "Expectations of SQL queries was not met.")
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.