Go语言 如何模拟返回JSON响应的http.Client

edqdpe6u  于 2023-06-19  发布在  Go
关注(0)|答案(4)|浏览(110)

我正在尝试测试一个使用net/http发出请求的方法。具体来说,我试图实现的是注入一个模拟http.Client,它用特定的JSON主体响应

type clientMock struct{}

func (c *clientMock) Do(req *http.Request) (*http.Response, error) {
  json := struct {
    AccessToken string `json:"access_token`
    Scope       string `json:"scope"`
  }{
    AccessToken: "123457678",
    Scope:       "read, write",
  }
  body := json.Marshal(json)
  res := &http.Response {
    StatusCode: http.StatusOK,
    Body:       // I haven't got a clue what to put here
  }
  return res
}

func TestRequest(t *testing.T) { //tests here }

我知道Bodyio.ReadCloser接口类型。麻烦的是,我找不到一种方法来实现它在模拟身体的React。
到目前为止,here的示例仅演示了返回空白&http.Response{}

ijnw1ujt

ijnw1ujt1#

虽然使用httptest.Server模拟完整的请求周期可能更有用,但您可以使用ioutil.NopCloser在任何读取器周围创建更接近的:

Body: ioutil.NopCloser(bytes.NewReader(body))

如果你想要一个空的正文,只需提供一个没有内容的阅读器。

Body: ioutil.NopCloser(bytes.NewReader(nil))
xuo3flqw

xuo3flqw2#

在测试文件(my_test.go)中:

type MyJSON struct {
        Id          string
        Age         int
}

// Interface which is the same as httpClient because it implements "Do" method.
type ClientMock struct {}

func (c *ClientMock) Do(req *http.Request) (*http.Response, error) {
    mockedRes := MyJSON {"1", 3}

    // Marshal a JSON-encoded version of mockedRes
    b, err := json.Marshal(mockedRes)
    if err != nil {
        log.Panic("Error reading a mockedRes from mocked client", err)
    }

    return &http.Response{Body: ioutil.NopCloser(bytes.NewBuffer(b))}, nil
}

// your test which will use the mocked response
func TestMyFunction(t *testing.T) {

    mock := &ClientMock{}
    actualResult := myFunction(mock)
    assert.NotEmpty(t, actualResult, "myFunction should have at least 1 result")

}

在你的实现中(main.go):

package main

import (
    "net/http"
)

func main() {
    myFunction(&http.Client{})
}
u0njafvf

u0njafvf3#

我知道这是一个小的一段时间,但我只是写了一些东西,以帮助这最近。
像JimB一样,我建议在本地启动一个真实的的HTTP服务器,因为在Go中,这很容易用https://golang.org/pkg/net/http/httptest/来完成。
然而,在做了很多HTTP mocking之后,我想要做得更多一点的东西,就像一个好的mock库一样:返回特定数据、容易地设置期望、验证所有请求都已发出等。我通常使用https://godoc.org/github.com/stretchr/testify/mock进行模拟,并希望具有这样的功能。
所以我写了https://github.com/dankinder/httpmock,它基本上结合了两者。如果您只是想要一个接受JSON并输出JSON的mock,那么这可能是一种更简单的方法。

xhv8bpkk

xhv8bpkk4#

您可以执行以下操作:

    • 在你的客户端。去**
var cl HTTPClient

type HTTPClient interface {
    Do(req *http.Request) (*http.Response, error)
}

func init() {
    cl = &http.Client{}
}

func Start() error {
    // jsonData: Some JSON marshalled data
    // Url: Some HTTP URL

    req, err := http.NewRequest(http.MethodPost, Url, bytes.NewBuffer(jsonData))
    if err != nil {
        log.Printf("Error in creating new HTTP request: %v", err)
        return err
    }
    req.Header.Set("Content-Type", "application/json")

    resp, err := cl.Do(req)
    if err != nil {
        log.Printf("Error in sending HTTP request: %v", err)
        return err
    }
    defer resp.Body.Close()
    log.Printf("Successfully sent HTTP request")
    return nil
}
    • 在client_test. go中**
const errHttpFake = "fake HTTP Error"

type mockDoType func(req *http.Request) (*http.Response, error)

type mockClient struct {
    mockDo mockDoType
}

func (m *mockClient) Do(req *http.Request) (*http.Response, error) {
    return m.mockDo(req)
}

func getHttpFailureClient() {
    req := io.NopCloser(bytes.NewReader([]byte(mockResult)))
    cl = &mockClient{
        mockDo: func(*http.Request) (*http.Response, error) {
            return &http.Response{
                StatusCode: 404,
                Body:       req,
            }, errors.New(errHttpFake)
        },
    }
}

func getHttpSuccessClient() {
    req := io.NopCloser(bytes.NewReader([]byte(mockResult)))
    cl = &mockClient{
        mockDo: func(*http.Request) (*http.Response, error) {
            return &http.Response{
                StatusCode: 200,
                Body:       req,
            }, nil
        },
    }
}

func TestHttpSuccess(t *testing.T) {
    getHttpSuccessClient()
    errHttp := Start() //Replace with function name containing client.Do()
    assert.Nil(t, errHttp)
}

func TestHttpClientFailure(t *testing.T) {
    getHttpFailureClient()
    errHttp := Start() //Replace with function name containing client.Do()
    assert.NotNil(t, errHttp)
}

相关问题