英文:
How to record argument values called to a mock function
问题
我正在尝试获取调用的参数值到一个模拟函数中。Go的模拟库是否有类似于Jest
中的someMockFunction.mock.calls[0][0]).toBe('first arg')
或Mockito
中的ArgumentCaptor
的功能?
这是我的使用案例。
我有一个Client
结构体,调用外部API。
func (c *Client) SubmitForm(ctx context.Context ) (string, error) {
formVals := url.Values{}
// 在这里创建payload
apiUrl := url.URL{Scheme: "http", Host: "api.mytestservice.com", Path: "/submit"}
httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, apiUrl.String(), strings.NewReader(formVals.Encode()))
httpReq.Header.Set("Authorization", <sometoken>)
httpReq.Header.Set("Content-Type", "application/x-www-form-urlencoded")
resp, err := c.httpClient.Do(ctx, submitPickupSchedule, httpReq) // 这里调用了一个模拟的httpClient.Do()
// 错误处理和返回值在这里
return resp, err
}
我的模拟使用了Mockery
(我也尝试过Mockgen
)。
mockHTTPClient := mock_httputils.NewMockHTTPClient(ctrl)
client = Client{httpClient: mockHTTPClient} // 在这里使用了模拟的HTTP客户端
t.Run("should call the Do with post request successfully", func(t *testing.T) {
ctx := context.Background()
ctx = context.WithValue(ctx, utils.CTXAuthTokenKey, "value")
mockHTTPClient.EXPECT().Do(ctx, "SubmitCall",
gomock.Any()).Return(&http.Response{StatusCode: http.StatusOK, Body: io.NopCloser(bytes.NewReader([]byte("SUCCESS")))}, nil)
resp, err := client.SubmitForm(ctx)
// 在这里进行断言,一切都按预期工作。它调用了模拟方法。
}
在调用模拟的Do()
之后,我想要获取传递给这个函数的实际参数。也就是说,我想要检查在SubmitForm
方法内部创建并传递给模拟的Do()
的req
对象。
在Go语言中是否有一种方法可以做到这一点?
英文:
I am trying to get the called argument values to a mock function. Does Go mock have a functionality similar to someMockFunction.mock.calls[0][0]).toBe('first arg')
in Jest
or ArgumentCaptor
in Mockito
?
Here's my use case.
I have a Client
struct that calls an external API.
func (c *Client) SubmitForm(ctx context.Context ) (string, error) {
formVals := url.Values{}
// Payload created here
apiUrl := url.URL{Scheme: "http", Host: "api.mytestservice.com, Path: "/submit"}
httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, apiUrl.String(), strings.NewReader(formVals.Encode()))
httpReq.Header.Set("Authorization", <sometoken>)
httpReq.Header.Set("Content-Type", "application/x-www-form-urlencoded")
resp, err := c.httpClient.Do(ctx, submitPickupSchedule, httpReq) // This calls to a mock httpClient.Do()
// error handling and return values goes here
return resp, err
}
And my mocks created with Mockery
(I tried Mockgen
as well. )
mockHTTPClient := mock_httputils.NewMockHTTPClient(ctrl)
client = Client{httpClient: mockHTTPClient} // Using the mock HTTP client here
t.Run("should call the Do with post request successfully", func(t *testing.T) {
ctx := context.Background()
ctx = context.WithValue(ctx, utils.CTXAuthTokenKey, "value")
mockHTTPClient.EXPECT().Do(ctx, "SubmitCall",
gomock.Any()).Return(&http.Response{StatusCode: http.StatusOK, Body: io.NopCloser(bytes.NewReader([]byte("SUCCESS")))}, nil)
resp, err := client.SubmitForm(ctx)
// assertions here and everything works as expected. It calls the mock method.
}
After calling the mock Do()
I am trying to get the actual arguments that got called into this function. i.e., I want to inspect the req
object that was created within the SubmitForm
method and passed into this mock Do()
.
Is there a way in GoLang to do this?
答案1
得分: 1
根据@mkopriva的评论,我能够在模拟函数中捕获参数。我在这里发布我的解决方案,希望能帮助到将来的任何人。
func TestArgumentCaptor(t *testing.T){
var req *http.Request // 用于记录请求属性
// 原始的HTTPClient Do(ctx context.Context, name string, req *http.Request) (resp *http.Response, err error) 的签名
mockHTTPClient.EXPECT().Do(ctx, "Submit", gomock.Any()).DoAndReturn(
// 匿名函数的签名必须与原始方法的签名相同
func(argCtx context.Context, argName string, argReq *http.Request) (resp *http.Response, err error) {
req = argReq
return &http.Response{StatusCode: http.StatusOK, Body: io.NopCloser(bytes.NewReader([]byte("SUCCESS")))}, nil
})
mockHTTPClient.DoCall() // 调用 mockHTTPClient.Do() 方法。
// 检查 URI
assert.NotNil(t, req)
assert.Equal(t, req.URL.Scheme, <expected-scheme>, "URL scheme mismatch")
assert.Equal(t, req.URL.Host, <expected-hist>, "Host mismatch")
assert.Equal(t, req.URL.Path, <expected-path>, "Path mismatch")
// 检查 Headers
assert.Equal(t, req.Header.Get("Authorization"),<expected-header>)
assert.Equal(t, req.Header.Get("Content-Type"), <expected-header>)
}
英文:
Following @mkopriva's comment, I was able to capture arguments in a mock function. Posting my solution here so it might help anyone in the future.
func TestArgumentCaptor(t *testing.T){
var req *http.Request // To record the request attributes
// Original HTTPClient Do(ctx context.Context, name string, req *http.Request) (resp *http.Response, err error) has this signature
mockHTTPClient.EXPECT().Do(ctx, "Submit", gomock.Any()).DoAndReturn(
// signature of the anonymous function must have the same method signature as the original method
func(argCtx context.Context, argName string, argReq *http.Request) (resp *http.Response, err error) {
req = argReq
return &http.Response{StatusCode: http.StatusOK, Body: io.NopCloser(bytes.NewReader([]byte("SUCCESS")))}, nil
})
mockHTTPClient.DoCall() // Calls the mockHTTPClient.Do() method.
// URI check
assert.NotNil(t, req)
assert.Equal(t, req.URL.Scheme, <expected-scheme>, "URL scheme mismatch")
assert.Equal(t, req.URL.Host, <expected-hist>, "Host mismatch")
assert.Equal(t, req.URL.Path, <expected-path>, "Path mismatch")
// Headers check
assert.Equal(t, req.Header.Get("Authorization"),<expected-header>)
assert.Equal(t, req.Header.Get("Content-Type"), <expected-header>)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论