如何使用httprouter编写测试代码

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

How to write test with httprouter

问题

我正在为GoLang中的一个简单REST服务编写测试。但是,由于我在使用julienschmidt/httprouter作为路由库,我在如何编写测试方面遇到了困难。

main.go

package main

func main() {
   router := httprouter.New()
   bookController := controllers.NewBookController()
   router.GET("/book/:id", bookController.GetBook)
   http.ListenAndServe(":8080", router)
}

controllers

package controllers

type BookController struct {}

func NewBookController *BookController {
   return &BookController()
}

func (bc BookController) GetBook(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
   fmt.Fprintf(w, "%s", p)
}

我的问题是:在GetBook既不是HttpHandler也不是HttpHandle的情况下,我该如何进行测试?

如果我使用传统的处理程序,测试将很容易,像这样:

func TestGetBook(t *testing.T) {
  req, _ := http.NewRequest("GET", "/book/sampleid", nil)
  rr := httptest.NewRecorder()
  handler := controllers.NewBookController().GetBook
  handler.ServeHTTP(rr, req)
  if status := rr.code; status != http.StatusOK {
    t.Errorf("Wrong status")
  }
}

问题是,httprouter既不是处理程序也不是handlefunc。所以我现在陷入了困境。

英文:

I am writing tests for a simple REST service in GoLang. But, because I am using julienschmidt/httprouter as the routing library. I am struggling on how to write test.

main.go

package main

func main() {
   router := httprouter.New()
   bookController := controllers.NewBookController()
   router.GET("/book/:id", bookController.GetBook)
   http.ListenAndServe(":8080", router)
}

controllers

package controllers

type BookController struct {}

func NewBookController *BookController {
   return &BookController()
}

func (bc BookController) GetBook(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
   fmt.Fprintf(w,"%s", p)
}

My question is: How can test this while GetBook is neither HttpHandler nor HttpHandle

If I use a traditional handler, the test will be easy like this

func TestGetBook(t *testing.T) {
  req, _ := http.NewRequest("GET", "/book/sampleid", nil)
  rr := httptest.NewRecorder()
  handler := controllers.NewBookController().GetBook
  handler.ServeHTTP(rr,req)
  if status := rr.code; status != http.StatusOK {
    t.Errorf("Wrong status")
  }
}

The problem is, httprouter is not handler, or handlefunc. So I am stuck now

答案1

得分: 16

为每个测试启动一个新的路由器,然后在测试下注册处理程序,然后将测试请求传递给路由器,而不是处理程序,以便路由器可以解析路径参数并将它们传递给处理程序。

func TestGetBook(t *testing.T) {
    handler := controllers.NewBookController()
    router := httprouter.New()
    router.GET("/book/:id", handler.GetBook)

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

    router.ServeHTTP(rr, req)
    if status := rr.Code; status != http.StatusOK {
        t.Errorf("Wrong status")
    }
}

请注意,这是一个示例代码片段,用于测试获取书籍的处理程序。在测试中,我们创建了一个新的路由器和处理程序,并发送一个GET请求到/book/sampleid路径。然后,我们检查响应的状态码是否为200(http.StatusOK)。

英文:

Just spin up a new router for each test and then register the handler under test, then pass the test request to the router, not the handler, so that the router can parse the path parameters and pass them to the handler.

func TestGetBook(t *testing.T) {
    handler := controllers.NewBookController()
    router := httprouter.New()
    router.GET("/book/:id", handler.GetBook)

	req, _ := http.NewRequest("GET", "/book/sampleid", nil)
	rr := httptest.NewRecorder()
	
	router.ServeHTTP(rr, req)
	if status := rr.Code; status != http.StatusOK {
		t.Errorf("Wrong status")
	}
}

答案2

得分: 3

你需要将你的处理程序包装起来,以便可以将其作为http.HandlerFunc访问:

func TestGetBook(t *testing.T) {
    req, _ := http.NewRequest("GET", "/book/sampleid", nil)
    rr := httptest.NewRecorder()
    handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        controllers.NewBookController().GetBook(w, r, httprouter.Params{})
    })
    handler.ServeHTTP(rr, req)
    if status := rr.Code; status != http.StatusOK {
        t.Errorf("Wrong status")
    }
}

如果你的处理程序需要参数,你可以手动从请求中解析它们,或者将它们作为第三个参数提供。

英文:

You need to wrap your handler so that it can be accessed as an http.HandlerFunc:

func TestGetBook(t *testing.T) {
    req, _ := http.NewRequest("GET", "/book/sampleid", nil)
    rr := httptest.NewRecorder()
    handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        controllers.NewBookController().GetBook(w, r, httprouter.Params{})
    })
    handler.ServeHTTP(rr,req)
    if status := rr.code; status != http.StatusOK {
        t.Errorf("Wrong status")
    }
}

If your handler requires parameters, you'll either have to parse them manually from the request, or just supply them as the third argument.

答案3

得分: 1

你可以尝试在不使用ServeHTTP的情况下进行以下操作:

func TestGetBook(t *testing.T) {
    req := httptest.NewRequest("GET", "http://example.com/foo", nil)
    w := httptest.NewRecorder()

    controllers.NewBookController().GetBook(w, req, []httprouter.Param{{Key: "id", Value: "101"}})

    resp := w.Result()
    body, _ := ioutil.ReadAll(resp.Body)

    t.Log(resp.StatusCode)
    t.Log(resp.Header.Get("Content-Type"))
    t.Log(string(body))
}

这段代码用于测试获取书籍信息的功能。它创建了一个模拟的HTTP请求,并将其发送到http://example.com/foo。然后,它调用controllers.NewBookController().GetBook方法来处理该请求,并将结果写入w(一个httptest.ResponseRecorder对象)。最后,它从响应中读取状态码、Content-Type头和响应体,并将它们记录到测试日志中。

英文:

u can try this without ServeHTTP

func TestGetBook(t *testing.T) {
	req := httptest.NewRequest("GET", "http://example.com/foo", nil)
	w := httptest.NewRecorder()

	controllers.NewBookController().GetBook(w, req, []httprouter.Param{{Key: "id", Value: "101"}})

	resp := w.Result()
	body, _ := ioutil.ReadAll(resp.Body)

	t.Log(resp.StatusCode)
	t.Log(resp.Header.Get("Content-Type"))
	t.Log(string(body))
}

答案4

得分: -1

这是另一个很好的博客和相应的工作代码:

https://medium.com/@gauravsingharoy/build-your-first-api-server-with-httprouter-in-golang-732b7b01f6ab

https://github.com/gsingharoy/httprouter-tutorial/blob/master/part4/handlers_test.go

英文:

here is one more good blog and corresponding working code for this:

> https://medium.com/@gauravsingharoy/build-your-first-api-server-with-httprouter-in-golang-732b7b01f6ab
>
> https://github.com/gsingharoy/httprouter-tutorial/blob/master/part4/handlers_test.go

huangapple
  • 本文由 发表于 2017年4月20日 01:31:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/43502432.html
匿名

发表评论

匿名网友

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

确定