6

I use go-sqlmock (https://godoc.org/github.com/DATA-DOG/go-sqlmock) to test a function that receives a variable number of arguments (I simplified the function for the sake of simplicity and stripped out most of the code):

func getHits(db *sql.DB, actions ...string) (hits []Hit, err error) {
   // ...
   query := `select * from table where action in (?,?)`
   rows, err := db.Query(query, actions)
   // ...
}

The tests look like that:

// rows := ...
actions := []string{"click", "event"}
mock.ExpectQuery(`^select .*`).WithArgs(actions).WillReturnRows(rows)
hits, err := getHits(db, actions...)
if mockErr := mock.ExpectationsWereMet(); mockErr != nil {
    log.Fatalf("there were unfulfilled expections: %s", mockErr)
}

Then I get this output:

2017/12/21 10:38:23 there were unfulfilled expections: there is a remaining expectation which was not matched: ExpectedQuery => expecting Query or QueryRow which:
- matches sql: '^select .*'
- is with arguments:
  0 - [click event]
- should return rows: ...

If I change the tests like this:

mock.ExpectQuery(`^select .*`).WithArgs(actions[0], actions[1]).WillReturnRows(rows)

Then I get this output:

2017/12/21 10:44:41 there were unfulfilled expections: there is a remaining expectation which was not matched: ExpectedQuery => expecting Query or QueryRow which:
- matches sql: '^select .*'
- is with arguments:
  0 - click
  1 - event
- should return rows:

The only I can make it pass is by calling :

db.Query(query, actions[0], actions[1])

which is what I obviously don't want to do as I don't know the number of actions...

Does anyone have an idea on how I could fix or debug this ?

7
  • Does actions... not work? Commented Dec 21, 2017 at 11:31
  • @Flimzy nope; the compiler complains : cannot use actions (type []string) as type []driver.Value in argument to mock.ExpectQuery("^select .*").WithArgs Commented Dec 21, 2017 at 11:51
  • Convert actions to type []driver.Value then. Commented Dec 21, 2017 at 12:53
  • @Flimzy unfortunately this yields exactly the same output as in case 2. Commented Dec 21, 2017 at 13:44
  • Sorry, which is case 2? Commented Dec 21, 2017 at 13:57

3 Answers 3

5

Accepted answer using []interface{} would work for string but it can throw an error for other types.

Short answer

actions := []driver.Value{"click", "event"}
mock.ExpectQuery(`^select .*`).WithArgs(actions...).WillReturnRows(rows)

Long answer

The argument requires driver.Value reference and driver.Value can be one of these types:

  • int64
  • float64
  • bool
  • []byte
  • string
  • time.Time

so, the correct answer is

actions := []driver.Value{"click", "event"}
mock.ExpectQuery(`^select .*`).WithArgs(actions...).WillReturnRows(rows)
Sign up to request clarification or add additional context in comments.

2 Comments

if int64 is in the types allowed in driver.Value, then why won't a []int64 work?
You could do []driver.Value{<int64>, <int64>,...}
3

A much cleaner solution would be to use this.

/* Prepare database mock */
type AnyNumber struct{}

// Match satisfies sqlmock.Argument interface
func (a AnyNumber) Match(v driver.Value) bool {
    _, ok := v.(float64)
    return ok
}

And then use AnyNumber{} as the argument in WithArgs

Here is the reference in the docs Click Here

Comments

2

I found a way to fix my problem : If I convert the slice of strings to a slice of interfaces for db.Query, it works just fine:

boundValues := make([]interface{}, len(actions))

for i, val := range actions {
    boundValues[i] = val
}

rows, err := db.Query(query, boundValues...)

Then for the tests:

mock.ExpectQuery(`^select .*`).WithArgs(actions[0], actions[1]).WillReturnRows(rows)

NOTE: passing just db.Query(query, actions...) does not work; this results in cannot use actions (type []string) as type []interface {} in argument to db.Query

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.