The Go Blog 02 :httptest 的介绍与使用

httptest 的介绍与使用
我们在写完接口之后都需要对接口进行测试, 在 golang 标准库中提供 httptest 包来辅助测试。

因为接口都是需要 IP 地址或域名来访问, httptest 包中默认定义了服务地址

const DefaultRemoteAddr = “1.2.3.4”
1
重要的方法
NewRequest(请求体)
NewRequest 方法用来创建一个 http 的请求体。

方法定义:

func NewRequest(method, target string, body io.Reader) *http.Request
1
method 参数表示测试的接口的 HTTP 方法。
target 参数表示接口定义的路由。
body 参数表示请求体。
NewRecorder(响应体)
方法定义:

func NewRecorder() *ResponseRecorder
1
NewRecorder 方法用来创建 http 的响应体。返回的类型是 *httptest.ResponseRecorder , 包含接口返回信息, 等价于 http.ResponseWriter。

ResponseRecorder 类型定义:

type ResponseRecorder struct {
// http 响应码.
Code int
// 头部信息
HeaderMap http.Header
// 返回的 Body
Body *bytes.Buffer
// 是否调用 Flush 方法
Flushed bool
}
1
2
3
4
5
6
7
8
9
10
NewServer(http 服务)
方法定义:

func NewServer(handler http.Handler) *Server
1
NewServer 方法用来创建和启动新的服务。同类的还有 NewTLSServer, 用来创建带 SSL 的服务。

type Server struct {
URL string // 服务地址
Listener net.Listener
// TLS 配置信息
TLS *tls.Config
Config *http.Server
}
1
2
3
4
5
6
7
测试 next/http 库创建的接口
请求接口定义:

func testAPI(w http.ResponseWriter, r *http.Request){}
1
测试方法定义:

func Test_testApi(t *testing.T) {
tests := []struct {
name string
}{
{
name: “test api”,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(testAPI))
defer ts.Close()

        params := struct{
            "params" string 
        }{
            "params": "paramsBody"
        }
        paramsByte, _ := json.Marshal(params)

        resp, err := http.Post(ts.URL, "application/json", bytes.NewBuffer(paramsByte))
        if err != nil {
            t.Error(err)
        }
        defer resp.Body.Close()

        t.Log(resp.StatusCode)
        if resp.StatusCode != http.StatusCreated && resp.StatusCode != http.StatusOK {
            body, _ := ioutil.ReadAll(resp.Body)
            t.Error(string(body))
        }
    })
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
测试时通过 httptest.NewServer 创建一个 testAPI 接口的服务。然后通过 http.Post 方法来调用我们创建的服务, 达到接口测试时请求的目的。然后判断接口返回的信息是否正确。

Golang httptest
上面一个例子很有用, 但是如何去发送一个真正的 http request 而不去真正的启动一个 http server(亦或者请求任意的 server)? 答案是使用 Go 的 httptest 包, 这个包可以非常简单的创建一个测试的 http server, 那么下面我们将展示一下完整的代码, 并解释一下整体的测试流程:

person.go:

package person

import (
“net/http”
“fmt”
“io/ioutil”
“encoding/json”

"github.com/astaxie/beego/logs"

)

const (
ADDRESS = “shanghai”
)

type Person struct {
Name string json:"name"
Address string json:"address"
Age int json:"age"
}

func GetInfo(api string) ([]Person, error) {
url := fmt.Sprintf(“%s/person?addr=%s”, api, ADDRESS)
resp, err := http.Get(url)

defer resp.Body.Close()

if err != nil {
	return []Person{}, err
}

if resp.StatusCode != http.StatusOK {
	return []Person{}, fmt.Errorf("get info didn’t respond 200 OK: %s", resp.Status)
}

bodyBytes, _ := ioutil.ReadAll(resp.Body)
personList := make([]Person,0)
err = json.Unmarshal(bodyBytes, &personList)
if err != nil {
	logs.Error("decode data fail")
	return []Person{}, fmt.Errorf("decode data fail")
}

return personList, nil

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
person_test.go:

package person

import (
“testing”
“net/http/httptest”
“net/http”
“fmt”
“encoding/json”
)

var personResponse = []Person{
{
Name : “wahaha”,
Address : “shanghai”,
Age : 20,
},
{
Name : “lebaishi”,
Address : “shanghai”,
Age : 10,
},
}

var personResponseBytes, _ = json.Marshal(personResponse)

func TestPublishWrongResponseStatus(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write(personResponseBytes)
if r.Method != “GET”{
t.Errorf(“Expected’GET’request, got’%s’”, r.Method)
}
if r.URL.EscapedPath() != “/person” {
t.Errorf(“Expected request to’/person’, got’%s’”, r.URL.EscapedPath())
}
r.ParseForm()
topic := r.Form.Get(“addr”)
if topic != “shanghai” {
t.Errorf(“Expected request to have’addr=shanghai’, got:‘%s’”, topic)
}
}))

defer ts.Close()
api := ts.URL
fmt.Println("url:", api)
resp, _ := GetInfo(api)

fmt.Println("reps:", resp)

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
解释一下:

我们通过 httptest.NewServer 创建了一个测试的 http server
读请求设置通过变量 r *http.Request, 写变量 (也就是返回值) 通过 w http.ResponseWriter
通过 ts.URL 来获取请求的 URL(一般都是 http://ip:port)
通过 r.Method 来获取请求的方法, 来测试判断我们的请求方法是否正确
获取请求路径: r.URL.EscapedPath(), 本例中的请求路径就是 /person
获取请求参数: r.ParseForm, r.Form.Get(“addr”)
设置返回的状态码: w.WriteHeader(http.StatusOK)
设置返回的内容 (这就是我们想要的结果): w.Write(personResponseBytes), 注意 w.Write() 接收的参数是 []byte, 因此需要将 object 对象列表通过 json.Marshal(personResponse) 转换成字节。
How does one test net.Conn in unit tests in Golang?
You might be able to do what you need with net.Pipe which basically gives you both ends of a connection (think, after .Accept())

server, client := net.Pipe()
go func() {
// Do some stuff
server.Close()
}()

// Do some stuff
client.Close()
————————————————
版权声明:本文为CSDN博主「云满笔记」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wan212000/article/details/121657780

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值