Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
iswbm committed Mar 26, 2022
1 parent fc8641e commit d245c88
Show file tree
Hide file tree
Showing 4 changed files with 936 additions and 3 deletions.
82 changes: 82 additions & 0 deletions source/c08/c08_03.md
@@ -1,2 +1,84 @@
# 8.3 测试技巧:网络测试

### 1. TCP/HTTP

假设需要测试某个 API 接口的 handler 能够正常工作,例如 helloHandler

``` go 
func helloHandler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("hello world"))
}
```

那我们可以创建真实的网络连接进行测试:

```go
// 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` 进行测试更为高效。

上述的测试用例改写如下:

```go
// 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),达到了相同的目的。
88 changes: 88 additions & 0 deletions source/c08/c08_03.rst
@@ -1,2 +1,90 @@
8.3 测试技巧:网络测试
======================

1. TCP/HTTP
~~~~~~~~~~~

假设需要测试某个 API 接口的 handler 能够正常工作,例如 helloHandler

.. code::  go 

func helloHandler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("hello world"))
}
那我们可以创建真实的网络连接进行测试:

.. code:: go
// 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``
进行测试更为高效。

上述的测试用例改写如下:

.. code:: go
// 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),达到了相同的目的。

0 comments on commit d245c88

Please sign in to comment.