您的位置:首页 > 理论基础 > 计算机网络

golang web开发 Handler测试利器httptest

2017-10-16 11:43 387 查看
test是golang语言的一部分,golang提供了非常强大的测试方法。单元测试,压力测试可以参见 golang 1.7之后高级测试方法之子测试,子基准测试(subtest sub-benchmarks)

我们用go开发一个Web Server后,打算单元测试写的handler函数,在不知道httptest之前,使用比较笨的方法

就是编译运行该Web Server后,再用go编写一个客户端程序向该Web Server对应的route发送数据然后解析

返回的数据。这个方法测试时非常麻烦,使用httptest来测试的话就非常简单,可以和testing测试一起使用。

httptest基本使用方法

假设在server中handler已经写好

http.HandleFunc("/health-check", HealthCheckHandler)

func HealthCheckHandler(w http.ResponseWriter, r *http.Request) {
// A very simple health check.
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json")

// In the future we could report back on the status of our DB, or our cache
// (e.g. Redis) by performing a simple PING, and include them in the response.
io.WriteString(w, `{"alive": true}`)
}


测试如下:

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

func TestHealthCheckHandler(t *testing.T) {
//创建一个请求
req, err := http.NewRequest("GET", "/health-check", nil)
if err != nil {
t.Fatal(err)
}

// 我们创建一个 ResponseRecorder (which satisfies http.ResponseWriter)来记录响应
rr := httptest.NewRecorder()

//直接使用HealthCheckHandler,传入参数rr,req
HealthCheckHandler(rr, req)

// 检测返回的状态码
if status := rr.Code; status != http.StatusOK {
t.Errorf("handler returned wrong status code: got %v want %v",
status, http.StatusOK)
}

// 检测返回的数据
expected := `{"alive": true}`
if rr.Body.String() != expected {
t.Errorf("handler returned unexpected body: got %v want %v",
rr.Body.String(), expected)
}
}


然后就可以使用run test来执行测试.

如果Web Server有操作数据库的行为,需要在init函数中进行数据库的连接。

参考官方文档中的样例编写的另外一个测试代码:

func TestHealthCheckHandler2(t *testing.T) {
reqData := struct {
Info string `json:"info"`
}{Info: "P123451"}

reqBody, _ := json.Marshal(reqData)
fmt.Println("input:", string(reqBody))
req := httptest.NewRequest(
http.MethodPost,
"/health-check",
bytes.NewReader(reqBody),
)

req.Header.Set("userid", "wdt")
req.Header.Set("commpay", "brk")

rr := httptest.NewRecorder()
HealthCheckHandler(rr, req)

result := rr.Result()

body, _ := ioutil.ReadAll(result.Body)
fmt.Println(string(body))

if result.StatusCode != http.StatusOK {
t.Errorf("expected status 200,",result.StatusCode)
}
}


注意不同的地方

- http.NewRequest替换为httptest.NewRequest。

- httptest.NewRequest的第三个参数可以用来传递body数据,必须实现io.Reader接口。

- httptest.NewRequest不会返回error,无需进行err!=nil检查。

- 解析响应时没直接使用ResponseRecorder,而是调用了Result函数。

结合context使用

func TestGetProjectsHandler(t *testing.T) {
req, err := http.NewRequest("GET", "/api/users", nil)
if err != nil {
t.Fatal(err)
}

rr := httptest.NewRecorder()
// e.g. func GetUsersHandler(ctx context.Context, w http.ResponseWriter, r *http.Request)
handler := http.HandlerFunc(GetUsersHandler)

// Populate the request's context with our test data.
ctx := req.Context()
ctx = context.WithValue(ctx, "app.auth.token", "abc123")
ctx = context.WithValue(ctx, "app.user",
&YourUser{ID: "qejqjq", Email: "user@example.com"})

// Add our context to the request: note that WithContext returns a copy of
// the request, which we must assign.
req = req.WithContext(ctx)
handler.ServeHTTP(rr, req)

// Check the status code is what we expect.
if status := rr.Code; status != http.StatusOK {
t.Errorf("handler returned wrong status code: got %v want %v",
status, http.StatusOK)
}
}


参考

httptest doc

Testing Your (HTTP) Handlers in Go
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: