如何记录调用到模拟函数的参数值

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

How to record argument values called to a mock function

问题

我正在尝试获取调用的参数值到一个模拟函数中。Go的模拟库是否有类似于Jest中的someMockFunction.mock.calls[0][0]).toBe('first arg')Mockito中的ArgumentCaptor的功能?

这是我的使用案例。

我有一个Client结构体,调用外部API。

  1. func (c *Client) SubmitForm(ctx context.Context ) (string, error) {
  2. formVals := url.Values{}
  3. // 在这里创建payload
  4. apiUrl := url.URL{Scheme: "http", Host: "api.mytestservice.com", Path: "/submit"}
  5. httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, apiUrl.String(), strings.NewReader(formVals.Encode()))
  6. httpReq.Header.Set("Authorization", <sometoken>)
  7. httpReq.Header.Set("Content-Type", "application/x-www-form-urlencoded")
  8. resp, err := c.httpClient.Do(ctx, submitPickupSchedule, httpReq) // 这里调用了一个模拟的httpClient.Do()
  9. // 错误处理和返回值在这里
  10. return resp, err
  11. }

我的模拟使用了Mockery(我也尝试过Mockgen)。

  1. mockHTTPClient := mock_httputils.NewMockHTTPClient(ctrl)
  2. client = Client{httpClient: mockHTTPClient} // 在这里使用了模拟的HTTP客户端
  3. t.Run("should call the Do with post request successfully", func(t *testing.T) {
  4. ctx := context.Background()
  5. ctx = context.WithValue(ctx, utils.CTXAuthTokenKey, "value")
  6. mockHTTPClient.EXPECT().Do(ctx, "SubmitCall",
  7. gomock.Any()).Return(&http.Response{StatusCode: http.StatusOK, Body: io.NopCloser(bytes.NewReader([]byte("SUCCESS")))}, nil)
  8. resp, err := client.SubmitForm(ctx)
  9. // 在这里进行断言,一切都按预期工作。它调用了模拟方法。
  10. }

在调用模拟的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(&#39;first arg&#39;) in Jest or ArgumentCaptor in Mockito?

Here's my use case.

I have a Client struct that calls an external API.

  1. func (c *Client) SubmitForm(ctx context.Context ) (string, error) {
  2. formVals := url.Values{}
  3. // Payload created here
  4. apiUrl := url.URL{Scheme: &quot;http&quot;, Host: &quot;api.mytestservice.com, Path: &quot;/submit&quot;}
  5. httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, apiUrl.String(), strings.NewReader(formVals.Encode()))
  6. httpReq.Header.Set(&quot;Authorization&quot;, &lt;sometoken&gt;)
  7. httpReq.Header.Set(&quot;Content-Type&quot;, &quot;application/x-www-form-urlencoded&quot;)
  8. resp, err := c.httpClient.Do(ctx, submitPickupSchedule, httpReq) // This calls to a mock httpClient.Do()
  9. // error handling and return values goes here
  10. return resp, err
  11. }

And my mocks created with Mockery (I tried Mockgen as well. )

  1. mockHTTPClient := mock_httputils.NewMockHTTPClient(ctrl)
  2. client = Client{httpClient: mockHTTPClient} // Using the mock HTTP client here
  3. t.Run(&quot;should call the Do with post request successfully&quot;, func(t *testing.T) {
  4. ctx := context.Background()
  5. ctx = context.WithValue(ctx, utils.CTXAuthTokenKey, &quot;value&quot;)
  6. mockHTTPClient.EXPECT().Do(ctx, &quot;SubmitCall&quot;,
  7. gomock.Any()).Return(&amp;http.Response{StatusCode: http.StatusOK, Body: io.NopCloser(bytes.NewReader([]byte(&quot;SUCCESS&quot;)))}, nil)
  8. resp, err := client.SubmitForm(ctx)
  9. // assertions here and everything works as expected. It calls the mock method.
  10. }

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的评论,我能够在模拟函数中捕获参数。我在这里发布我的解决方案,希望能帮助到将来的任何人。

  1. func TestArgumentCaptor(t *testing.T){
  2. var req *http.Request // 用于记录请求属性
  3. // 原始的HTTPClient Do(ctx context.Context, name string, req *http.Request) (resp *http.Response, err error) 的签名
  4. mockHTTPClient.EXPECT().Do(ctx, "Submit", gomock.Any()).DoAndReturn(
  5. // 匿名函数的签名必须与原始方法的签名相同
  6. func(argCtx context.Context, argName string, argReq *http.Request) (resp *http.Response, err error) {
  7. req = argReq
  8. return &http.Response{StatusCode: http.StatusOK, Body: io.NopCloser(bytes.NewReader([]byte("SUCCESS")))}, nil
  9. })
  10. mockHTTPClient.DoCall() // 调用 mockHTTPClient.Do() 方法。
  11. // 检查 URI
  12. assert.NotNil(t, req)
  13. assert.Equal(t, req.URL.Scheme, <expected-scheme>, "URL scheme mismatch")
  14. assert.Equal(t, req.URL.Host, <expected-hist>, "Host mismatch")
  15. assert.Equal(t, req.URL.Path, <expected-path>, "Path mismatch")
  16. // 检查 Headers
  17. assert.Equal(t, req.Header.Get("Authorization"),<expected-header>)
  18. assert.Equal(t, req.Header.Get("Content-Type"), <expected-header>)
  19. }
英文:

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.

  1. func TestArgumentCaptor(t *testing.T){
  2. var req *http.Request // To record the request attributes
  3. // Original HTTPClient Do(ctx context.Context, name string, req *http.Request) (resp *http.Response, err error) has this signature
  4. mockHTTPClient.EXPECT().Do(ctx, &quot;Submit&quot;, gomock.Any()).DoAndReturn(
  5. // signature of the anonymous function must have the same method signature as the original method
  6. func(argCtx context.Context, argName string, argReq *http.Request) (resp *http.Response, err error) {
  7. req = argReq
  8. return &amp;http.Response{StatusCode: http.StatusOK, Body: io.NopCloser(bytes.NewReader([]byte(&quot;SUCCESS&quot;)))}, nil
  9. })
  10. mockHTTPClient.DoCall() // Calls the mockHTTPClient.Do() method.
  11. // URI check
  12. assert.NotNil(t, req)
  13. assert.Equal(t, req.URL.Scheme, &lt;expected-scheme&gt;, &quot;URL scheme mismatch&quot;)
  14. assert.Equal(t, req.URL.Host, &lt;expected-hist&gt;, &quot;Host mismatch&quot;)
  15. assert.Equal(t, req.URL.Path, &lt;expected-path&gt;, &quot;Path mismatch&quot;)
  16. // Headers check
  17. assert.Equal(t, req.Header.Get(&quot;Authorization&quot;),&lt;expected-header&gt;)
  18. assert.Equal(t, req.Header.Get(&quot;Content-Type&quot;), &lt;expected-header&gt;)
  19. }

huangapple
  • 本文由 发表于 2023年1月11日 18:17:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/75081446.html
匿名

发表评论

匿名网友

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

确定