【问题标题】:Conditional Mocking in GoGo 中的条件模拟
【发布时间】:2021-08-13 17:31:30
【问题描述】:

我想根据特定条件在 GoLang 中模拟 Rest API 调用。 例如,我有一个定义如下的方法:

func Method() {
  resp1, err := DoSomething1()
  resp2, err := DoSomething2()
}

func DoSomething1() (*http.Response, error) {
  return Get(url string)
}

func DoSomething2() (*http.Response, error) {
  return Get(url string)
}

现在,我想分别为每个 get 调用定义我的模拟响应。即当我从 Method() 调用 DoSomething1() 时,我想模拟 get 调用并返回响应 R1,当我从 Method() 调用 DoSomething2() 时,我想模拟 get 调用并返回响应 R2。

到目前为止,我已经能够通过将 Get 定义为接口并对其进行模拟来模拟单个 get 调用,该调用将为任何请求返回相同的响应,但是我正在尝试为每个调用定义响应。

下面是我定义的用于模拟 get/post 调用的模拟接口:

package clientMock

import (
    "net/http"
)

type MockClient struct {
}

var (
    GetMock  func(url string, queryParams map[string]interface{}, headerParams map[string]interface{}) (*http.Response, error)
    PostMock func(url string, reqBody interface{}, queryParams map[string]interface{}, headerParams map[string]interface{}) (*http.Response, error)
)

func (m MockClient) Get(url string, queryParams map[string]interface{}, headerParams map[string]interface{}) (*http.Response, error) {
    return GetMock(url, queryParams, headerParams)
}

func (m MockClient) Post(url string, reqBody interface{}, queryParams map[string]interface{}, headerParams map[string]interface{}) (*http.Response, error) {
    return PostMock(url, reqBody, queryParams, headerParams)
}

下面是我为测试 Method 定义的示例测试类,但是无法弄清楚当从 Method() 调用 DoSomething2() 时如何更改模拟响应:

func TestHandleSuccess(t *testing.T) {

    resBody := `{"instance_url":"instance_url","access_token":"access_token"}`
    r := ioutil.NopCloser(bytes.NewReader([]byte(resBody)))
    clientMock.GetMock = func(url string, queryParams, headerParams map[string]interface{}) (*http.Response, error) {
        return &http.Response{
            StatusCode: 200,
            Body:       r,
        }, nil

    }

    err := method.Method()
    assert.Nil(t, err)
}

【问题讨论】:

    标签: unit-testing go


    【解决方案1】:

    鉴于您提供的代码,我猜从您的“做某事”函数传递到 Get 的参数 url 是不同的(否则我不确定您为什么需要改变行为)。如果是这种情况,您可以在模拟中添加一个条件来更改基于 url 的行为。

    clientMock.GetMock = func(url string, queryParams, headerParams map[string]interface{}) (*http.Response, error) {
        var resBody string
        if url == "/call1" {
            resBody = `{"instance_url":"instance_url","access_token":"access_token"}`
        } else if url == "/call2" {
            resBody = `{"something":"else"}`
        }
        return &http.Response{
            StatusCode: 200,
            Body:       ioutil.NopCloser(bytes.NewReader([]byte(resBody))),
        }, nil
    }
    

    这就是您应该如何看待您的代码 - 行为不应根据调用的来源而改变。相反,它应该根据被调用函数的输入而改变。这将您的函数与其调用者分离,并使重用和重构更容易。

    【讨论】:

    • 是的,你是对的,每次调用的 URL 都会不同。感谢您提供解决方案,这对我有很大帮助。
    猜你喜欢
    • 2013-10-10
    • 2015-08-17
    • 2023-03-09
    • 2019-02-18
    • 1970-01-01
    • 2012-12-20
    • 2010-12-30
    • 2015-03-08
    • 1970-01-01
    相关资源
    最近更新 更多