如何使用带有可变数量参数的go-sqlmock WithArgs()?

时间:2017-12-21 09:52:11

标签: go

我使用go-sqlmock(https://godoc.org/github.com/DATA-DOG/go-sqlmock)来测试一个接收可变数量参数的函数(为了简单起见我简化了函数并删除了大部分代码):

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

测试看起来像这样:

// 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)
}

然后我得到了这个输出:

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: ...

如果我改变这样的测试:

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

然后我得到了这个输出:

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:

唯一能让它通过的是致电:

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

这是我显然不想做的事情,因为我不知道行动的数量......

有没有人知道如何修复或调试它?

3 个答案:

答案 0 :(得分:2)

使用[]interface{}接受的答案适用于字符串,但它可能会为其他类型引发错误。

简短回答

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

答案很长

论证需要driver.Value reference,而driver.Value可以是其中之一types

  • 的int64
  • float64
  • BOOL
  • []字节
  • 字符串
  • 了time.time

所以,正确答案是

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

答案 1 :(得分:1)

我找到了解决问题的方法:如果我将字符串切换转换为db.Query的一个接口片段,它可以正常工作:

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

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

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

然后进行测试:

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

注意:仅传递db.Query(query, actions...)不起作用;这导致cannot use actions (type []string) as type []interface {} in argument to db.Query

答案 2 :(得分:0)

一种更清洁的解决方案是使用它。

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

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

然后使用AnyNumber{}作为WithArgs中的参数

此处是文档Click Here

中的参考