对于句子
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()时,它可以返回我之前设置的响应。 出于某种原因,我不能在这里嘲笑客户。
答案 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
}