8.3 测试技巧:网络测试¶
1. TCP/HTTP¶
假设需要测试某个 API 接口的 handler 能够正常工作,例如 helloHandler
func helloHandler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("hello world"))
}
那我们可以创建真实的网络连接进行测试:
// test code
import (
"io/ioutil"
"net"
"net/http"
"testing"
)
func handleError(t *testing.T, err error) {
t.Helper()
if err != nil {
t.Fatal("failed", err)
}
}
func TestConn(t *testing.T) {
ln, err := net.Listen("tcp", "127.0.0.1:0")
handleError(t, err)
defer ln.Close()
http.HandleFunc("/hello", helloHandler)
go http.Serve(ln, nil)
resp, err := http.Get("http://" + ln.Addr().String() + "/hello")
handleError(t, err)
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
handleError(t, err)
if string(body) != "hello world" {
t.Fatal("expected hello world, but got", string(body))
}
}
net.Listen("tcp", "127.0.0.1:0")
:监听一个未被占用的端口,并返回 Listener。调用
http.Serve(ln, nil)
启动 http 服务。使用
http.Get
发起一个 Get 请求,检查返回值是否正确。尽量不对
http
和net
库使用 mock,这样可以覆盖较为真实的场景。
2. httptest¶
针对 http 开发的场景,使用标准库 net/http/httptest
进行测试更为高效。
上述的测试用例改写如下:
// test code
import (
"io/ioutil"
"net/http"
"net/http/httptest"
"testing"
)
func TestConn(t *testing.T) {
req := httptest.NewRequest("GET", "http://example.com/foo", nil)
w := httptest.NewRecorder()
helloHandler(w, req)
bytes, _ := ioutil.ReadAll(w.Result().Body)
if string(bytes) != "hello world" {
t.Fatal("expected hello world, but got", string(bytes))
}
}
使用 httptest 模拟请求对象(req)和响应对象(w),达到了相同的目的。