如何在golang中向httptest.server注入一个url?

时间:2017-10-26 00:37:56

标签: unit-testing go gomock

对于句子

resp, err := client.Get(fmt.Sprintf("https://www.xxxxx/day?time=%s", time))

如果我想在单元测试中模拟对此client.Get()的响应,我应该使用httptest.server,但是如何将url(https://www.xxxxx/day?time=%s)绑定到httptest.server的url?所以当我调用client.Get()时,它可以返回我之前设置的响应。 出于某种原因,我不能在这里嘲笑客户。

3 个答案:

答案 0 :(得分:2)

你通常不这样做。您从服务器获取基本URL并将其提供给客户端:

package main

import (
    "fmt"
    "net/http"
    "net/http/httptest"
    "testing"
    "time"
)

func TestClient(t *testing.T) {
    server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            // Verify request, send mock response, etc.
    }))

    defer server.Close()

    var client *http.Client
    var time time.Time

    baseURL := server.URL // Something like "http://127.0.0.1:53791"
    resp, err := client.Get(fmt.Sprintf(baseURL+"/day?time=%s", time))
    if err != nil {
            t.Fatal(err)
    }

    // Verify response body if applicable

    resp.Body.Close()
}

答案 1 :(得分:0)

http.Client是一个结构而不是一个接口,如你所见,它使得模拟变得困难。模拟它的另一种方法是传递例程所需的外部依赖项,因此不使用client.Get,而是使用clientGet - 这是一个传递给例程的函数指针。

然后,您可以通过单元测试创​​建:

mockClientGet(c *http.client, url string) (resp *http.Response, err error) {
// add the test code to return what you want it to.
}

然后在您的主要代码中使用:

resp, err := clientGet(client, fmt.Sprintf("https://www.xxxxx/day?time=%s", time))

正常调用该过程时,请使用指向http.Client.Get的函数指针,并将测试传递给指向mock的指针。它并不理想,但我没有看到一个更好的方法来模拟非接口外部调用 - 并且考虑到它的外部依赖性,从外部注入它并不是一件坏事。

答案 2 :(得分:0)

func NewTestServerWithURL(URL string, handler http.Handler) (*httptest.Server, error) {
    ts := httptest.NewUnstartedServer(handler)
    if URL != "" {
        l, err := net.Listen("tcp", URL)
        if err != nil {
            return nil, err
        }
        ts.Listener.Close()
        ts.Listener = l
    }
    ts.Start()
    return ts, nil
}