测试 HTTP handler

在这节我们将学习如果用 Go 测试 HTTP handlers,这是一个用 Go 测试的特别例子。我们将已 www.go 的代码为基础,修改需要调整的地方。

新版本的 www.go 命名为 testWWW.go,并分为三部分展示。testWWW.go 的第一部分代码如下:

  1. package main
  2. import (
  3. "fmt"
  4. "net/http"
  5. "os"
  6. )
  7. func CheckStatusOK(w http.ResponseWriter, r *http.Request){
  8. w.WriteHeader(http.StatusOK)
  9. fmt.Fprintf(w, `Fine!`)
  10. }

testWWW.go 的第二部分代码如下:

  1. func StatusNotFound(w http.ResponseWriter, r *http.Request) {
  2. fmt.Fprintf(w, "Serving: %s\n", r.URL.Path)
  3. fmt.Printf("Served: %s\n", r.Host)
  4. }
  5. func MyHandler(w http.ResponseWriter, r *http.Request) {
  6. fmt.Fprintf(w, "Serving: %s\n", r.URL.Path)
  7. fmt.Printf("Served: %s\n", r.Host)
  8. }

testWWW.go 余下代码如下:

  1. func main() {
  2. PORT := ":8001"
  3. arguments := os.Args
  4. if len(arguments) == 1 {
  5. fmt.Println("Using default port number:", PORT)
  6. } else {
  7. PORT = ":" + arguments[1]
  8. }
  9. http.HandleFunc("/CheckStatusOK", CheckStatusOK)
  10. http.HandleFunc("/StatusNotFound", StatusNotFound)
  11. http.HandleFunc("/", MyHandler)
  12. err := http.ListenAndServe(PORT, nil)
  13. if err != nil {
  14. fmt.Println(err)
  15. return
  16. }
  17. }

我们现在需要开始测试 testWWW.go 了,为此我们应该创建一个 testWWW_test.go 文件。这个文件的内容由四部分展示。

testWWW_test.go 的第一部分包容如下代码:

  1. package main
  2. import (
  3. "fmt"
  4. "net/http"
  5. "net/http/httptest"
  6. "testing"
  7. )

注意,为了用 Go 测试 web 应用,您需要引入 net/http/httptest 标准包。

testWWW_tesst.go 的第二部分如下:

  1. func TestCheckStatusOK(t *testing.T) {
  2. req, err := http.NewRequest("GET", "/CheckStatusOK", nil)
  3. if err != nil {
  4. fmt.Println(err)
  5. return
  6. }
  7. rr := httptest.NewRecorder()
  8. handler := http.HandlerFunc(CheckStatusOK)
  9. handler.ServeHTTP(rr, req)

httptest.NewRecorder() 函数返回一个 httptest.ResponseRecorder 对象,它被用于记录 HTTP 响应。

testWWW_test.go 的第三部分如下:

  1. status := rr.Code
  2. if status != http.StatusOK {
  3. t.Errorf("handler returned %v", status)
  4. }
  5. expect := `Fine!`
  6. if rr.Body.String() != expect {
  7. t.Errorf("handler returned %v", rr.Body.String())
  8. }
  9. }

您首先检查返回码是所期望的,然后再验证返回消息体也是您期望的。

testWWW_test.go 的余下代码如下:

  1. func TestStatusNotFound(t *testing.T) {
  2. req, err := http.NewRequest("GET", "/StatusNotFound", nil)
  3. if err != nil {
  4. fmt.Println(err)
  5. return
  6. }
  7. rr := httptest.NewRecorder()
  8. handler := http.HandlerFunc(StatusNotFound)
  9. handler.ServeHTTP(rr, req)
  10. status := rr.Code
  11. if status != http.StatusNotFound {
  12. t.Errorf("handler returned %v", status)
  13. }
  14. }

这个测试函数验证 main 包中的 StatusNotFound() 函数是否如期运行。

执行 testWWW_test.go 的这俩个测试函数将产生如下输出:

  1. $ go test testWWW.go testWWW_test.go -v
  2. === RUN TestCheckStatusOK
  3. --- PASS: TestCheckStatusOK (0.00s)
  4. === RUN TestStatusNotFound
  5. --- PASS: TestStatusNotFound (0.00s)
  6. PASS
  7. ok command-line-arguments (cached)