我有以下功能:
func getPrice(date string) {
url := (fmt.Printf("http://endponint/%s", date))
resp, err := http.Get(url)
// Unmarshall body and get price
return price
}
为了对这个函数进行单元测试,我不得不重构为:
func getPrice(client HTTPClient, date string) {
url := (fmt.Printf("http://endponint/%s", date))
resp, err := client.Get(url)
// Unmarshall body and get price
return price
}
我的测试是这样的:
type MockClient struct {
Response *http.Response
Err error
}
func (m *MockClient) Get(url string) (*http.Response, error) {
return m.Response, m.Err
}
mockResp := &http.Response{
StatusCode: http.StatusOK,
Body: ioutil.NopCloser(strings.NewReader("mock response")),
}
client := &MockClient{
Response: mockResp,
Err: nil,
}
data, err := getData(client, "http://example.com")
这是在 golang 中测试的唯一方法吗,没有办法模拟未注入函数的 API 吗?
提前致谢。
使用 Go 进行 HTTP 测试的惯用方法是使用 http/httptest(examples)
在您的情况下,您需要做的就是使基本 URL 可注入:
var APIEndpoint = "http://endpoint/"
func getPrice(date string) (int, error) {
url := (fmt.Printf("%s/%s", APIEndpoint, date))
resp, err := http.Get(url)
// Unmarshall body and get price
return price, nil
}
然后在每个测试中:
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Write the expected response to the writer
}))
defer srv.Close()
APIEndpoint = srv.URL
price, err := getPrice("1/1/2023")
// Handle error, check return
稍微好一点的设计是将您的 API 包装在客户端中
struct
并使 getPrice
成为接收方方法:
type PriceClient struct {
Endpoint string
}
func (pc *PriceClient) GetPrice(date string) (int, error) {
url := (fmt.Printf("%s/%s", pc.Endpoint, date))
resp, err := http.Get(url)
// Unmarshall body and get price
return price, nil
}
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Write the expected response to the writer
}))
defer srv.Close()
c := &PriceClient{Endpoint: srv.URL}
price, err := c.GetPrice("1/1/2023")
// Handle error, check return
为了将来参考,您还应该看看 gomock,因为您将遇到的大多数其他模拟问题都没有语言内置的解决方案。