Mar 28, 2020

Testing Web Applications in Go

We all know that testing is one of the most important tasks when writing our software. Creating unit tests of pure functions is straightforward. You set up your test function, assert that the response matches your expectations and call it a day. Testing your request handlers sounds more difficult, or does it?

Built on the fact that people would use it for building internet-scale web services, Go's standard library includes the package net/http/httptest, which is everything needed to test your HTTP handler business logic as uncomplicated as writing a unit test for anything else.

I enjoyed the quick example from the official documentation, which is why I altered it slightly and will go ahead to use it for demonstration purposes:

package main

import (
  "io"
  "net/http"
)

func NewHandler() http.HandlerFunc {
  return func(w http.ResponseWriter, r *http.Request) {
    io.WriteString(w, "<html><body>Hello World!</body></html>")
  }
}

This function simply returns our handler func used by the router or multiplexer when we configure our server for the actual runtime. For testing, we only need the handler function to test it.

package main

import (
  "fmt"
  "io/ioutil"
  "net/http/httptest"
)

func TestNewHandler() {
  // Create handler
  handler := NewHandler()

  // Create and record request
  req := httptest.NewRequest("GET", "http://example.com/foo", nil)
  w := httptest.NewRecorder()
  handler(w, req)

  resp := w.Result()

  // Read response body
  body, _ := ioutil.ReadAll(resp.Body)

  // TODO Build assertions on response
  fmt.Println(resp.StatusCode)
  fmt.Println(resp.Header.Get("Content-Type"))
  fmt.Println(string(body))
}

As you can see, there's little code required to set up a test that will invoke your handler with an example request and assert some conditions on the generated response. All of this is done without having to worry about any networking quirks because we don't even have to spin up a server.

You can customize this further to set up a testing suite that runs various requests against the handler, in the classic table-test fashion of inputs and expected outputs.


I hope you enjoyed this short guide on using the built-in testing helpers for web applications. If you've got any questions, suggestions, or feedback in general, don't hesitate to reach out on Twitter or by mail.