如何使用gomock让Mock函数在多次调用时返回不同结果?
问题:gomock多次调用Mock函数返回不同结果失败
使用gomock模拟被测函数中的HTTP Post调用时,单次调用正常,但希望第二次调用返回不同结果时,程序始终调用第一个Mock函数。尝试按顺序设置多个Mock调用后,出现调用次数超限的错误;改用.AnyTimes()后,又会重复调用第一个Mock导致响应体重复读取引发EOF错误。
当前代码:
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 < 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... )
遇到的错误:
Unexpected call to *mock_rpc.MockHttp.Post because [function] has already been called the max number of times
改用.AnyTimes()后,出现EOF错误(因响应体被重复读取)。
解决方案
问题根源在于循环创建的每个Mock调用都使用了任意参数匹配器,gomock无法区分这些调用的顺序匹配逻辑,导致第一个调用被耗尽后直接报错。以下两种方式可以解决问题:
方式一:同一Mock调用定义多组返回值(参数一致的场景)
当每次调用的参数匹配规则相同时,无需创建多个独立的EXPECT()调用,直接在Return()中按顺序传入多组返回值,并指定总调用次数即可:
ctrl := gomock.NewController(t) defer ctrl.Finish() mockHttp := mock_http.NewMockHttp(ctrl) // 按调用顺序收集所有返回值(每组包含响应和错误) var returnVals []interface{} for i := 0; i < len(tc.mockHttpResps); i++ { returnVals = append(returnVals, tc.mockHttpResps[i], tc.mockHttpErrs[i]) } // 定义一次Post Mock,指定多次调用的返回值和总次数 mockHttp.EXPECT().Post(gomock.Any(), gomock.Any(), gomock.Any()). Return(returnVals...). Times(len(tc.mockHttpResps))
方式二:指定参数匹配+顺序约束(参数不同的场景)
如果每次调用的参数有差异,需要为每个调用单独定义EXPECT()并指定精确的参数匹配器,再用gomock.InOrder()严格约束调用顺序:
ctrl := gomock.NewController(t) defer ctrl.Finish() mockHttp := mock_http.NewMockHttp(ctrl) // 为每次调用定义独立的Mock,指定匹配参数和返回值 call1 := mockHttp.EXPECT().Post("target-url-1", gomock.Any(), gomock.Any()).Return(tc.mockHttpResps[0], tc.mockHttpErrs[0]).Times(1) call2 := mockHttp.EXPECT().Post("target-url-2", gomock.Any(), gomock.Any()).Return(tc.mockHttpResps[1], tc.mockHttpErrs[1]).Times(1) // 强制按顺序执行Mock调用 gomock.InOrder(call1, call2)
核心注意点
- 同一方法、相同参数匹配规则的多次调用,直接通过
Return()传入多组返回值即可,gomock会按顺序依次返回。 - 若参数不同,必须为每个调用单独设置
EXPECT()并指定参数匹配器,否则gomock无法区分调用对应关系。
内容的提问来源于stack exchange,提问作者124141251
相关产品推荐
相关产品推荐

