golang web开发 Handler测试利器httptest

前端之家收集整理的这篇文章主要介绍了golang web开发 Handler测试利器httptest前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

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,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",http.StatusOK)
    }
}

参考

httptest doc
Testing Your (HTTP) Handlers in Go

推荐干货满满的技术专栏

[toc]

原文链接:https://www.f2er.com/go/187839.html

猜你在找的Go相关文章