In our projects we have a lot of tests. Http Api tests are one of the most important parts of any testing.

Error Messages, Status Codes and Responses should be tested very careful.

This article contains:

Preparations

Test case

The magic function

The test

Conclusion

We will use a github.com/gorilla/mux for url routing.

Preparations

We are going to test a User handler. A handler which responses with a User profile.

func User(w http.ResponseWriter, r *http.Request) { ... }

The router:

import ( "github.com/gorilla/mux" ) func NewRouter() (s *mux.Router) { s = mux.NewRouter() userHandler := s.PathPrefix("/user/").Subrouter() userHandler.HandleFunc("/", UserRegister).Methods("POST").Name("UserRegister") userHandler.HandleFunc("/{user_id}/", User).Methods("GET", "HEAD").Name("User") return s }

Test case

In our test case we need to start a httptest.NewServer which will use a router:

import ( ... "net/http/httptest" "net/url" "testing" ... ) func TestUserRegistration(t *testing.T) { router := NewRouter() localServer := httptest.NewServer(router) defer localServer.Close() localServerUrl, err := url.Parse(localServer.URL) ... }

We've got a localServerUrl which points to our endpont.

The magic function

We need to form a url for committing a request. Let's write a function for it

import ( "github.com/gorilla/mux" "net/url" ) func MakeUrl(server_url *url.URL, router *mux.Router, urlName string, url_params []string, query_params map[string]string) (*url.URL, error) { // Get url from routing urlPtr, err := router.Get(urlName).URL( url_params..., ) if err != nil { return nil, err } // Get currently serving httptest url_I := *server_url // Join it's address and path of a specific url url_I.Path = urlPtr.Path q := url_I.Query() for k, v := range query_params { q.Set(k, v) } url_I.RawQuery = q.Encode() return &url_I, err }

This function makes Just Do It with an url :D

To form a url for getting a user's profile you need to call it:

url, err := MakeUrl( localServerUrl, router, "UserProfile", // <- HANDLER's NAME []string{ "user_id", 1234, // <- HANDLER's URL PARAMS: /users/123/ }, map[string]string{}{ "format": "json", // <- HANDLER URL QUERY: /users/123/?format=json }, ) Expect(err).NotTo(HaveOccurred())

Let's assume we have a complicated handler

entityHandler.HandleFunc("/{entity_id}/{entity_property:(.*[\\\\/]?)}/", http_handlers.PutEntityProperty()).Methods("PUT", "OPTIONS").Name("PutEntityProperty")

To make a request you need to

url, err := MakeUrl( localServerUrl, router, "PutEntityProperty", []string{ "entity_id", "users", "entity_property": "email" }, map[string]string{}{ }, ) Expect(err).NotTo(HaveOccurred())

The test

Our test will look like

email := generated_data["email"] url, err := test_helpers.MakeUrl( localServerUrl, router, "UserRegister", []string{}, map[string]string{}, ) request := &TestHttpRequest{} err := request.Post( url.String(), map[string]interface{}{ "Content-Type": "application/json" }, map[string]interface{}{ "email": email, "password": generated_data["password"], }, )

Conclusion