如何使用gomock使模拟函数在连续调用时返回不同的结果?

huangapple go评论86阅读模式
英文:

How to use gomock to make a mocked function return different results on subsequent calls?

问题

我正在使用gomock来模拟在被测试的函数中调用的http函数。虽然对于一次调用它运行得很好,但当我想在第二次调用时返回不同的结果时,它似乎再次调用了第一个函数(请参见下面的代码)。该函数会调用第一个模拟函数(在calls切片中)n次,所以我的问题是:如何使用gomock使模拟函数在后续调用中返回不同的结果?我参考了这个stackoverflow的帖子进行了尝试。

到目前为止,我有以下代码:

ctrl := gomock.NewController(t)
defer ctrl.Finish()

// Mock http client
mockHttp := mock_http.NewMockHttp(ctrl)

// 设置模拟调用的顺序
var calls []*gomock.Call
for i := 0; i < len(tc.mockHttpResps); i++ {
    // 注意:tc.mockHttpResps[i] 是一个 *http.Response{}
    fn := mockHttp.EXPECT().Post(gomock.Any(), gomock.Any(),gomock.Any()).Return(tc.mockHttpResps[i], tc.mockHttpErrs[i]).Times(1) 
    calls = append(calls, fn)
}
gomock.InOrder(
   calls...
)

但是它会产生以下错误:

Unexpected call to *mock_rpc.MockHttp.Post because [function] has already been called the max number of times

如果我尝试将调用设置为.AnyTimes(),那么错误就会消失,但第一个模拟函数仍然被多次调用。然后我会遇到其他错误,比如EOF,因为http.Response的body被读取了两次,这是可以预料的。

注意:我尝试按照链接的帖子中的方法进行操作,但结果仍然出现相同的错误。

英文:

I am using gomock to mock an http function that is called within the function under test. While it works great for one call it seems to call the first function again when I want to return a different result on the second call (see code below). The function calls the first mocked function (in calls slice) n number of times, so my question is: How can I use gomock to make a mocked function return different results on subsequent calls? I used this stackoverflow post for inspiration.

This is what I have until now:

ctrl := gomock.NewController(t)
defer ctrl.Finish()

// Mock http client
mockHttp := mock_http.NewMockHttp(ctrl)

// set up order of mock calls
var calls []*gomock.Call
for i := 0; i &lt; len(tc.mockHttpResps); i++ {
    // Note: tc.mockHttpResps[i] is a *http.Response{}
    fn := mockHttp.EXPECT().Post(gomock.Any(), gomock.Any(),gomock.Any()).Return(tc.mockHttpResps[i], tc.mockHttpErrs[i]).Times(1) 
    calls = append(calls, fn)
}
gomock.InOrder(
   calls...
)

But it produces an error along these lines:

Unexpected call to *mock_rpc.MockHttp.Post because [function] has already been called the max number of times

If I try to set the calls to .AnyTimes() then the error goes away but the first mocked function is still called multiple times. I then get other errors such as EOF as the http.Response body is read twice, which is to be expected.

Note: I have tried to do exactly as in the linked post, but it leads to the same error.

答案1

得分: 1

JonathanHall指出,没有必要模拟HTTP客户端。

这是修订后的可工作代码:

cnt := 0
// 模拟HTTP服务器
svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    if tc.mockHttpErrs[cnt] != nil {
        w.WriteHeader(http.StatusBadRequest)
	    fmt.Fprintln(w, tc.mockHttpErrs[cnt].Error())
        cnt++
        return
    }
    fmt.Fprintf(w, tc.mockHttpResps[cnt])
    cnt++
}))
defer svr.Close()

// 使用svr.URL和svr.Client()将其注入到需要的代码中

这样还可以更灵活地处理响应,而不依赖于gomock!

英文:

As JonathanHall pointed out there is no need to mock http clients.

This is the revised and working code:

cnt := 0
// mock http server
svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    if tc.mockHttpErrs[cnt] != nil {
        w.WriteHeader(http.StatusBadRequest)
	    fmt.Fprintln(w, tc.mockHttpErrs[cnt].Error())
        cnt++
        return
    }
    fmt.Fprintf(w, tc.mockHttpResps[cnt])
    cnt++
}))
defer svr.Close()

// use svr.URL and svr.Client() to inject into whatever code needs it

This also allows you to be more flexible regarding the responses without relying on gomock!

huangapple
  • 本文由 发表于 2023年5月25日 01:19:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/76325992.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定