我有一个名为CreateObject的处理函数。此函数同时包含对我不控制的外部API的POST请求。如果我想对它进行单元测试,我遇到的问题是每次运行测试时我都无法将新对象发布到外部服务。所以我想知道是否有办法用Go或任何解决方法来模拟它。
非常感谢。
打包主要
func main() {
router := mux.NewRouter()
router.HandleFunc("/groups", services.CreateObject).Methods("POST")
c := cors.New(cors.Options{
AllowedOrigins: []string{"*"},
AllowCredentials: true,
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"},
AllowedHeaders: []string{"*"},
ExposedHeaders: []string{"*"},
})
handler := c.Handler(router)
http.ListenAndServe(":3000", handler)
打包对象
func CreateObject(w http.ResponseWriter, r *http.Request) {
var newobject Object
_ = json.NewDecoder(r.Body).Decode(&newobject )
//Do things
jsonStr, err := json.Marshal(newobject)
if err != nil {
fmt.Println(err)
return
}
req, err := http.NewRequest("POST", ExternalURL+"/object", bytes.NewBuffer(jsonStr))
if err != nil {
fmt.Println(err)
return
}
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
if resp.StatusCode < 200 || resp.StatusCode > 299 {
w.WriteHeader(resp.StatusCode)
w.Header().Set("Content-Type", "application/json")
w.Write(body)
} else {
w.WriteHeader(201)
}
}
答案 0 :(得分:1)
您有几个选择:
1)您可以定义一个具有http.Client导出方法集的接口。然后,您可以创建此类型的包级变量,默认为* http.Client。您不必在CreateObject中使用* http.Client,而是使用此变量。由于它是一个界面,您可以轻松地模拟客户端。界面如下所示:
type HTTPClient interface {
Do(req *http.Request) (*http.Response, error)
Get(url string) (resp *http.Response, err error)
Post(url string, contentType string, body io.Reader) (resp *http.Response, err error)
PostForm(url string, data url.Values) (resp *http.Response, err error)
Head(url string) (resp *http.Response, err error)
}
但是,由于您只调用Do(),因此您的模拟只需要为Do定义实际的测试实现。我们经常使用函数字段样式:
type MockClient struct {
DoFunc func(req *http.Request) (*http.Response, error)
// other function fields, if you need them
}
func (m MockClient) Do(req *http.Request) (r *http.Response, err error) {
if m.DoFunc != nil {
r, err = m.DoFunc(req)
}
return
}
// Define the other 4 methods of the HTTPclient as trivial returns
var mockClient HTTPClient = MockClient{
DoFunc: func(req *http.Request) (*http.Response, error) {
return nil, nil
},
}
var mockClientFail HTTPClient = MockClient{
DoFunc: func(req *http.Request) (*http.Response, error) {
return nil, fmt.Errorf("failed")
},
}
2)在localhost端口上站起来自己的HTTP模拟服务器,在测试中,将ExternalURL变量更改为指向它。这允许您实际测试拨号(这使其更像是功能测试而不是单元测试),同时仍然有效地模拟&#34;外部端点。
在任何一种情况下,请确保您还编写了一些回归测试,以确保外部端点仍然按预期工作。
编辑:每dm03514,Go已经内置了模拟HTTP服务器:https://golang.org/pkg/net/http/httptest/