Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write test with httprouter

Tags:

go

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

like image 296
JSNoob Avatar asked Apr 19 '17 17:04

JSNoob


3 Answers

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")
    }
}
like image 60
mkopriva Avatar answered Oct 19 '22 20:10

mkopriva


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.

like image 31
Flimzy Avatar answered Oct 19 '22 19:10

Flimzy


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))
}
like image 29
gaozhidf Avatar answered Oct 19 '22 19:10

gaozhidf