This article was originally published on Matt Silverlock’s personal site, and with their permission, we’re sharing it here for Codeship readers.

You’re building a web (HTTP) service in Go, and you want to unit test your handler functions. You’ve got a grip on Go’s net/http package, but you’re not sure where to start with testing that your handlers return the correct HTTP status codes, HTTP headers or response bodies.

Let’s walk through how you go about this, injecting the necessary dependencies, and mocking the rest.

A Basic Handler

We’ll start by writing a basic test: we want to make sure our handler returns a HTTP 200 (OK) status code. This is our handler:

// handlers.go package handlers // e.g. http.HandleFunc("/health-check", HealthCheckHandler) func HealthCheckHandler(w http.ResponseWriter, r *http.Request) { // A very simple health check. w.WriteHeader(http.StatusOK) w.Header().Set("Content-Type", "application/json") // In the future we could report back on the status of our DB, or our cache // (e.g. Redis) by performing a simple PING, and include them in the response. io.WriteString(w, `{"alive": true}`) }

As you can see, Go’s testing and httptest packages make testing our handlers extremely simple. We construct a *http.Request , a *httptest.ResponseRecorder , and then check how our handler has responded: status code, body, etc.

If our handler also expected specific query parameters or looked for certain headers, we could also test those:

Further, if you want to test that a handler (or middleware) is mutating the request in a particular way, you can define an anonymous function inside your test and capture variables from within by declaring them in the outer scope.

Tip: make strings like application/json or Content-Type package-level constants, so you don’t have to type (or typo) them over and over. A typo in your tests can cause unintended behavior, because you’re not testing what you think you are.

You should also make sure to test not just for success, but for failure too: test that your handlers return errors when they should (e.g. a HTTP 403, or a HTTP 500).

Populating context.Context in Tests

What about when our handlers are expecting data to be passed to them in a context.Context ? How we can create a context and populate it with (e.g.) an auth token and/or our User type?

Assumption: you have a custom handler type that provides a ServeHTTPC(context.Context, http.ResponseWriter, *http.Request) . Go 1.7 will add context.Context to http.Request , which will make this even easier.

Note that for the below example, I’m using the Goji mux/router for context.Context compatible handlers today, but this approach will work for any router/mux/framework that works with context.Context .

Mocking Database Calls

Our handlers expect that we pass them a datastore.ProjectStore (an interface type) with three methods (Create, Get, Delete). We want to stub this for testing so that we can test that our handlers (endpoints) return the correct status codes.

Stub out our database implementation: the unit tests in package handlers should not need a test database.

Create a stub that intentionally throws errors, so we can test that our handlers throw the right status code (e.g. a HTTP 500) and/or write the expected response.

How you might go about creating a ‘good’ stub that returns a (static) *datastore.Project and test that (for example) we can marshal it as JSON. This would catch the case where changes to the upstream type might cause it to be incompatible with encoding/json .