英文:
Golang: how to mock ...interface{} arguents using gomock
问题
我有一个使用标准go Printf
函数签名的 Printer
接口:
type Printer interface {
Printf(format string, tokens ...interface{})
}
我想使用 gomock 来模拟这个接口,但是我不确定如何正确设置 tokens ...interface{}
参数。
我原以为 Printf(gomock.Any(), gomock.Any())
可以覆盖所有可能的情况(因为 tokens
编译为 []interface{}
),但是似乎你需要为 N 个 token 设置一个明确的调用:
// 没有 token
mockPrinter.EXPECT().
Printf(gomock.Any()).
AnyTimes()
// 1 个 token
mockPrinter.EXPECT().
Printf(gomock.Any(), gomock.Any()).
AnyTimes()
// 2 个 token
mockPrinter.EXPECT().
Printf(gomock.Any(), gomock.Any(), gomock.Any()).
AnyTimes()
// ... 直到 N 个 token
有人知道有更好的方法吗?
<details>
<summary>英文:</summary>
I have a `Printer` interface that uses the standard go `Printf` function signature:
type Printer interface {
Printf(format string, tokens ...interface{})
}
I would like to be able to mock this interface using [gomock](https://github.com/golang/mock), but I'm not sure how setup the `tokens ...interface{}` argument properly.
I expected that `Printf(gomock.Any(), gomock.Any())` would cover all potential cases (since `tokens` compiles to `[]interface{}`), but it appears you need to setup an explicit call for N number of tokens:
// no tokens
mockPrinter.EXPECT().
Printf(gomock.Any()).
AnyTimes()
// 1 token
mockPrinter.EXPECT().
Printf(gomock.Any(), gomock.Any()).
AnyTimes()
// 2 tokens
mockPrinter.EXPECT().
Printf(gomock.Any(), gomock.Any(), gomock.Any()).
AnyTimes()
// ... up to N tokens
Does anyone know of a better way to do this?
</details>
# 答案1
**得分**: 2
当前版本的gomock不支持这个功能。也许你可以扩展它,并发送一个拉取请求。要理解为什么不可能,你需要查看为可变参数函数生成的模拟。
为了做到这一点,让我们看一下gomock存储库中的示例,特别是[./sample/mock_user/user.go][1]和[./sample/mock_user/mock_user.go][2]。
### 生成的模拟 ###
你会看到*Index*接口中有一个名为*Ellip*的函数,类似于你的*Printf*函数:
type Index interface {
// ...
Ellip(fmt string, args ...interface{})
// ...
}
现在,这是*Ellip*的模拟函数的样子:
func (_m *MockIndex) Ellip(_param0 string, _param1 ...interface{}) {
_s := []interface{}{_param0}
for _, _x := range _param1 {
_s = append(_s, _x)
}
_m.ctrl.Call(_m, "Ellip", _s...)
}
注意到什么奇怪的地方了吗?gomock创建了一个接口切片**_s**,用第一个参数进行初始化。然后它将可变参数追加到该接口切片**_s**中。
所以,明确一点,它不仅仅是将可变参数**_param1**追加到切片中。它通过迭代可变参数**_param1**,将每个单独的可变参数追加到新的切片中。
这意味着可变参数的切片并没有被保留下来。它被拆分了。
[1]: https://github.com/rafrombrc/gomock/blob/9dcd4b2cd01be60f9fbabacce2a6ae1ed21ea48f/sample/user.go
[2]: https://github.com/rafrombrc/gomock/blob/9dcd4b2cd01be60f9fbabacce2a6ae1ed21ea48f/sample/mock_user/mock_user.go
<details>
<summary>英文:</summary>
Not possible with the current version of gomock. Maybe you can extend it, and send a pull request in. To understand why it's not possible, you have to look at the mock generated for variadic functions.
To do that, let's look at the examples in gomock's repository, specifically [./sample/mock_user/user.go][1] and [./sample/mock_user/mock_user.go][2].
### Generated Mock ###
You'll see a function in the *Index* inteface called *Ellip*, which is like your *Printf* function:
type Index interface {
// ...
Ellip(fmt string, args ...interface{})
// ...
}
Now, here's what the mocked function looks like for *Ellip*:
func (_m *MockIndex) Ellip(_param0 string, _param1 ...interface{}) {
_s := []interface{}{_param0}
for _, _x := range _param1 {
_s = append(_s, _x)
}
_m.ctrl.Call(_m, "Ellip", _s...)
}
Notice anything odd? Well, gomock is creating a slice of interfaces, **_s**, initialized with the first parameter. Then it appends the variadic parameters to that slice of interfaces, **_s**.
So, to be clear, it doesn't just append the variadic parameter, **_param1**, to the slice. Each individual variadic from **_param1** is appended to the new slice, by iterating through it.
This means that the slice of variadic parameters is not preserved. It's broken out.
[1]: https://github.com/rafrombrc/gomock/blob/9dcd4b2cd01be60f9fbabacce2a6ae1ed21ea48f/sample/user.go
[2]: https://github.com/rafrombrc/gomock/blob/9dcd4b2cd01be60f9fbabacce2a6ae1ed21ea48f/sample/mock_user/mock_user.go
</details>
# 答案2
**得分**: 0
截至2017年10月1日,`gomock.Any()`对于可变参数的工作是正确的:https://github.com/golang/mock/pull/101
<details>
<summary>英文:</summary>
As of October 1, 2017, `gomock.Any()` works correctly for variadic args: https://github.com/golang/mock/pull/101
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论