如何将 go-sqlmock WithArgs() 与可变数量的参数一起使用?

Cyr*_*lle 6 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)
   // ...
}
Run Code Online (Sandbox Code Playgroud)

测试看起来像这样:

// 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)
}
Run Code Online (Sandbox Code Playgroud)

然后我得到这个输出:

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: ...
Run Code Online (Sandbox Code Playgroud)

如果我像这样改变测试:

mock.ExpectQuery(`^select .*`).WithArgs(actions[0], actions[1]).WillReturnRows(rows)
Run Code Online (Sandbox Code Playgroud)

然后我得到这个输出:

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:
Run Code Online (Sandbox Code Playgroud)

我唯一可以让它通过的是通过调用:

db.Query(query, actions[0], actions[1])
Run Code Online (Sandbox Code Playgroud)

这显然是我不想做的,因为我不知道操作的数量......

有谁知道我如何修复或调试这个问题?

tsu*_*suz 5

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

简短回答

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

长答案

该参数需要driver.Value 引用和 driver.Value 可以是以下类型之一:

  • 整型64
  • 浮动64
  • 布尔值
  • []字节
  • 细绳
  • 时间.时间

所以,正确答案是

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


Cyr*_*lle 2

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

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

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

rows, err := db.Query(query, boundValues...)
Run Code Online (Sandbox Code Playgroud)

然后进行测试:

mock.ExpectQuery(`^select .*`).WithArgs(actions[0], actions[1]).WillReturnRows(rows)
Run Code Online (Sandbox Code Playgroud)

注意:仅仅通过db.Query(query, actions...)是行不通的;这导致cannot use actions (type []string) as type []interface {} in argument to db.Query