我有两个结构:FunctionalityClient
和TestClient
,都是Interface
。我有一个Client
类型的全局变量Interface
。我将Client
分配给实际客户端或模拟客户端,具体取决于它是测试还是正常运行。
Interface
有一个我想在测试中模拟的方法Request
。也就是说,我想:
所以结构看起来像这样:
type TestClient struct {
recordedArgs []interface{}
returnValues []interface{}
}
func (c *TestClient) Request(body io.Reader, method string, endpoint string, headers []Header) ([]byte, error) {
c.recordedArgs = append(c.recordedArgs, []interface{}{body, method, endpoint, headers}) // this can't be typed if I want the code to be reusable
if len(c.returnValues) != 0 {
last := c.returnValues[0]
c.returnValues = c.returnValues[1:]
return last.([]byte), nil
}
return nil, nil
}
我这样使用它:
testClient := TestClient{
returnValues: []interface{}{
[]byte("arbitrarily defined return value"),
[]byte("this will be returned after calling Request a second time"),
}
}
Client = &testClient
// run the test
// now let's check the results
r1 := testClient.recordedArgs[1].([]interface{}) // because I append untyped lists to recordedArgs
assert.Equal(t, "POST", r1[1].(string))
assert.Equal(t, "/file", r1[2].(string))
// and so on
现在问题。
我有一些结构要我这样嘲笑。目前我只是为每个结构复制并粘贴上面的代码。但这真的很糟糕,我希望以某种方式抽象出模拟逻辑。我也会接受类似Mockito的when
之类的东西:当使用特定参数调用模拟函数时,返回一个特定值并记录调用。
如何在Golang中使用成员函数正确模拟结构?
答案 0 :(得分:0)
如果您要为HTTP API模拟客户端,您可能只想使用httptest.Server
,这会极大地简化这一过程。而不是模拟客户端,模拟客户端连接到的服务器。它非常易于使用,您仍然可以记录请求方法,路径,正文等,以及以与模拟客户端相同的方式返回任意响应值。
如果这不是一个选项,你可以抽象出你的模拟方法,使其可重复使用:
type TestClient struct {
recordedArgs [][]interface{}
returnValues []interface{}
}
func (c *TestClient) mock(args ...interface{}) interface{} {
c.recordedArgs = append(c.recordedArgs, args)
if len(c.returnValues) != 0 {
last := c.returnValues[0]
c.returnValues = c.returnValues[1:]
return last
}
return nil
}
func (c *TestClient) Request(body io.Reader, method string, endpoint string, headers []Header) ([]byte, error) {
return c.mock(body,method,endpoint,headers).([]byte), nil
}
这会将特定于使用情况的方法减少到一行。