Say I have a very simple Web service.
func main() {
http.HandleFunc("/", sanityTest)
log.Fatal(http.ListenAndServe(":8000", nil))
}
If I want to test it, I could minimally just have:
func ExampleTest() {
server := httptest.NewServer(http.DefaultServeMux)
defer server.Close()
resp, err := http.Get(server.URL)
if err != nil {
log.Fatal(err)
}
body, _ := ioutil.ReadAll(resp.Body)
fmt.Println(resp.StatusCode)
fmt.Println(resp.Header.Get("Content-Type"))
fmt.Println(string(body))
// Output:
// 200
// text/plain; charset=utf-8
// OK
}
But that will result in a 404, since it doesn't know about the routes. So what I've seen main_test.go code do, is re-setup the handles in the test file's init, like so:
func init() {
http.HandleFunc("/", sanityTest)
}
Which leads to duplication, and inevitably I have to create a function in main.go like:
func setupRoutes() {
http.HandleFunc("/", sanityTest)
}
Which I find a little ugly. Am I missing a trick to instantiate the routes from main.go and avoid the init?
You can re-use routes between tests and main.go file, also it's helpful if you want to mock something in your handlers (add a new argument to router()
func below)
main.go:
func sanityTest(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "%s", "sanity test")
}
func router() *http.ServeMux {
h := http.NewServeMux()
h.HandleFunc("/", sanityTest)
return h
}
func main() {
http.ListenAndServe(":8080", router())
}
main_test.go:
func TestSanity(t *testing.T) {
tests := []struct {
name string
uri string
want string
}{
{"1", "/", "sanity test"},
}
ts := httptest.NewServer(router())
defer ts.Close()
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
url := ts.URL + tt.uri
resp, _ := http.Get(url)
respBody, _ := ioutil.ReadAll(resp.Body)
resp.Body.Close()
got := string(respBody)
if got != tt.want {
t.Errorf("got %s, Want %s", got, tt.want)
}
})
}
}