如何在Golang中进行HTTP服务器的实时测试?

huangapple go评论86阅读模式
英文:

golang how to live test an http server?

问题

我使用了gotests和gorilla mux,可以对我的http handlefunc处理程序进行单元测试,但它们没有按照gorilla mux应有的方式响应正确的http请求方法。我该如何进行一个"实时服务器"版本的测试?

func main() {
    router := mux.NewRouter()
    router.HandleFunc("/", views.Index).Methods("GET")
}

func Index(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json; charset=UTF-8")
    w.WriteHeader(http.StatusOK)

    fmt.Fprintf(w, "INDEX\n")
}

func TestIndex(t *testing.T) {

    req, _ := http.NewRequest("GET", "/", nil)
    req1, _ := http.NewRequest("POST", "/", nil)
    rr := httptest.NewRecorder()

    handler := http.HandlerFunc(Index)

    type args struct {
        w http.ResponseWriter
        r *http.Request
    }
    tests := []struct {
        name string
        args args
    }{
        {name: "1: testing get", args: args{w: rr, r: req}},
        {name: "2: testing post", args: args{w: rr, r: req1}},
    }
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            handler.ServeHTTP(tt.args.w, tt.args.r)
            log.Println(tt.args.w)
        })
    }
}

问题在于该函数对GET和POST请求都进行了响应,并没有考虑到我的主路由。这对于单元测试函数来说是可以的,但我认为最好编写一个集成测试,一次性测试整个功能,并将所有东西一次性处理完毕。

英文:

I use gotests, and gorilla mux and I can unit test my http handlefunc handlers, but they do not respond to the proper http request methods as they should under the gorilla mux. How I can do a "live server" version of the test?

func main() {
	router := mux.NewRouter()
	router.HandleFunc("/", views.Index).Methods("GET")
}

func Index(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	w.WriteHeader(http.StatusOK)

	fmt.Fprintf(w, "INDEX\n")
}

func TestIndex(t *testing.T) {

	req, _ := http.NewRequest("GET", "/", nil)
	req1, _ := http.NewRequest("POST", "/", nil)
	rr := httptest.NewRecorder()

	handler := http.HandlerFunc(Index)

	type args struct {
		w http.ResponseWriter
		r *http.Request
	}
	tests := []struct {
		name string
		args args
	}{
		{name: "1: testing get", args: args{w: rr, r: req}},
		{name: "2: testing post", args: args{w: rr, r: req1}},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			handler.ServeHTTP(tt.args.w, tt.args.r)
			log.Println(tt.args.w)
		})
	}
}

The problem here is that the function responds to both the get and post requests and
doens't take into account my main router. This is fine for unit testing the function,
but I think it would be better to just write an integrated test that tests the whole
thing and gets everything out of the way in one go.

答案1

得分: 21

使用net/http/httptest.Server类型来与实际服务器进行测试。

func TestIndex(t *testing.T) {
  // 创建一个使用其他地方初始化的路由器的服务器。路由器可以是Gorilla mux,也可以是net/http ServeMux、http.DefaultServeMux或任何满足net/http Handler接口的值。
  ts := httptest.NewServer(router)
  defer ts.Close()

  newreq := func(method, url string, body io.Reader) *http.Request {
    r, err := http.NewRequest(method, url, body)
    if err != nil {
      t.Fatal(err)
    }
    return r
  }

  tests := []struct {
    name string
    r    *http.Request
  }{
    {name: "1: testing get", r: newreq("GET", ts.URL+"/", nil)},
    {name: "2: testing post", r: newreq("POST", ts.URL+"/", nil)}, // POST需要提供reader参数
  }
  for _, tt := range tests {
    t.Run(tt.name, func(t *testing.T) {
      resp, err := http.DefaultClient.Do(tt.r)
      defer resp.Body.Close()
      if err != nil {
        t.Fatal(err)
      }
      // 在这里检查预期的响应。
    })
  }
}

尽管问题中使用了Gorilla mux,但本答案中的方法和细节适用于任何满足http.Handler接口的路由器。

英文:

Use the net/http/httptest.Server type to test with a live server.

func TestIndex(t *testing.T) {
  // Create server using the a router initialized elsewhere. The router
  // can be a Gorilla mux as in the question, a net/http ServeMux, 
  // http.DefaultServeMux or any value that statisfies the net/http
  // Handler interface.
  ts := httptest.NewServer(router)  
  defer ts.Close()

  newreq := func(method, url string, body io.Reader) *http.Request {
	r, err := http.NewRequest(method, url, body)
	if err != nil {
		t.Fatal(err)
	}
	return r
  }

  tests := []struct {
	name string
	r    *http.Request
  }{
	{name: "1: testing get", r: newreq("GET", ts.URL+"/", nil)},
	{name: "2: testing post", r: newreq("POST", ts.URL+"/", nil)}, // reader argument required for POST
  }
  for _, tt := range tests {
	t.Run(tt.name, func(t *testing.T) {
		resp, err := http.DefaultClient.Do(tt.r)
		defer resp.Body.Close()
		if err != nil {
			t.Fatal(err)
		}
        // check for expected response here.
	})
  }
}

Although the question uses Gorilla mux, the approach and details in this answer apply to any router that satisfies the http.Handler interface.

huangapple
  • 本文由 发表于 2017年2月27日 05:05:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/42474259.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定