Golang:模拟响应测试HTTP客户端

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

Golang: mock response testing http client

问题

我是你的中文翻译助手,以下是翻译好的内容:

我是Golang的新手,正在尝试为一个简单的HTTP客户端编写测试。我在这里和其他地方都看到了很多方法,但似乎没有一个方法能够正常工作。我在模拟客户端响应方面遇到了问题。

这是我目前的客户端代码:

type API struct {
    Client  *http.Client
}

func (api *API) MyClient(qp string) ([]byte, error) {
    url := fmt.Sprintf("http://localhost:8000/myapi?qp=%s", qp)
    resp, err := api.Client.Get(url)
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)
    // 处理错误并对需要进行单元测试的body进行操作
    if err != nil {
        return nil, err
    }
    return body, err
}

这是我的测试函数:

func TestDoStuffWithTestServer(t *testing.T) {
    // 启动本地HTTP服务器
    server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
        rw.Write([]byte(`OK`))
    }))
    defer server.Close()

    // 使用我们本地测试服务器的Client和URL
    api := API{server.Client()}
    body, _ := api.MyClient("1d")

    fmt.Println(body)
}

正如我所说,这是它们目前的样子,因为我尝试了很多方法。

我的问题是,我无法模拟客户端的响应。在这个例子中,我的body是空的。我原以为rw.Write([]byte(OK))应该模拟响应。

英文:

i'm new to Golang and i'm trying to write a test for a simple HTTP client.
i read a lot of ways of doing so also here in SO but none of them seems to work.
I'm having troubles mocking the client response

This is how my client looks right now:

type API struct {
    Client  *http.Client
}

func (api *API) MyClient(qp string) ([]byte, error) {
    url := fmt.Sprintf("http://localhost:8000/myapi?qp=%s", qp)
    resp, err := api.Client.Get(url)
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)
    // handling error and doing stuff with body that needs to be unit tested
    if err != nil {
        return nil, err
    }
    return body, err
}

And this is my test function:

func TestDoStuffWithTestServer(t *testing.T) {
    // Start a local HTTP server
    server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
        rw.Write([]byte(`OK`))
    }))
    defer server.Close()

    // Use Client & URL from our local test server
    api := API{server.Client()}
    body, _ := api.MyClient("1d")



    fmt.Println(body)

}    

As i said, this is how they look right cause i try lot of ways on doing so.

My problem is that i'm not able to mock the client respose. in this example my body is empty. my understanding was that rw.Write([]byte(OK)) should mock the response 🤔

答案1

得分: 1

最终我是这样解决的:

myclient:

type API struct {
    Endpoint string
}

func (api *API) MyClient(slot string) ([]byte, error) {
    url := fmt.Sprintf("%s/myresource?qp=%s", api.Endpoint, slot)
    c := http.Client{}
    resp, err := c.Get(url)
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return nil, err
    }
    return body, err
}

test:

func TestDoStuffWithTestServer(t *testing.T) {
    server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
        rw.Write([]byte(`{Result: [{Cluster_name: "cl1", Pings: 2}]}`))
    }))

    defer server.Close()

    api := API{Endpoint: server.URL}
    res, _ := api.MyClient("1d")

    expected := []byte(`{Result: [{Cluster_name: "cl1", Pings: 2}]}`)

    if !bytes.Equal(expected, res) {
        t.Errorf("%s != %s", string(res), string(expected))
    }
}

不过,我还不确定这是否是在Go中正确的做法。

英文:

In the end i solved it like this:

myclient:

type API struct {
	Endpoint string
}

func (api *API) MyClient(slot string) ([]byte, error) {
	url := fmt.Sprintf("%s/myresource?qp=%s", api.Endpoint, slot)
	c := http.Client{}
	resp, err := c.Get(url)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	return body, err
}

test:

func TestDoStuffWithTestServer(t *testing.T) {
	server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
		rw.Write([]byte(`{Result: [{Cluster_name: "cl1", Pings: 2}]}`))
	}))

	defer server.Close()

	api := API{Endpoint: server.URL}
	res, _ := api.MyClient("1d")

	expected := []byte(`{Result: [{Cluster_name: "cl1", Pings: 2}]}`)

	if !bytes.Equal(expected, res) {
		t.Errorf("%s != %s", string(res), string(expected))
	}
}

still, not 100% sure is the right way of doing so in Go

huangapple
  • 本文由 发表于 2022年3月21日 16:43:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/71554819.html
匿名

发表评论

匿名网友

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

确定