Test Web API

Learn how to write unit tests on a web API, how to mock HTTP requests, and how to record HTTP responses.

Go fits well for testing web APIs. Thanks to the http package of the Go standard library, it is very easy to launch a web server and serve incoming requests. Whenever an HTTP request reaches our server, one handler is responsible for replying to it with the requested data. To get the data, each handler may call a database, a third-party system, and so on. However, to unit test our HTTP handlers, we don’t want to spin up an actual HTTP server.

The httptest package

The httptest package of the standard library provides us with everything we need to mock a request for our handlers. The interface that a handler has to implement is the following:

type Handler interface {
    ServeHTTP(ResponseWriter, *Request)
}

The ResponseWriter is an interface that contains all the methods used to construct the HTTP response. Conversely, the *Request includes all the HTTP request details that the client provides to the server. It’s pretty hard and time-consuming to mock these two things out. That’s why the httptest package provides the NewRequest function and the ResponseRecorder.

Mocking HTTP request

To mock out the HTTP request, we only need to call the NewRequest function, which returns an instance of the *http.Request type. The function’s signature is:

func NewRequest(method, target string, body io.Reader) *http.Request

It accepts the following arguments:

  • The HTTP method
  • The address of the resource to contact
  • The request payload, if any

After we instantiate and set up the request, we can focus on the server side.

Recording the HTTP response

Again, in the httptest package, we can take advantage of the capabilities provided by the ResponseRecorder type. To instantiate it, we have to invoke the following function:

func NewRecorder() *ResponseRecorder

The *ResponseRecorder is meant to be a drop-in replacement of a real HTTP server. As its name suggests, it records every HTTP response that might be asserted later by the test code. To get the actual *http.Response, we’ve to invoke the Result() method on an instance of the ResponseRecorder struct. The signature of the Result() method is as follows:

func (rw *ResponseRecorder) Result() *http.Response

When we retrieve an HTTP response, we’ll be able to assert its status code, the payload, the headers, and so on.

Ping Web API

Let’s start with a trivial example to understand how to unit test a basic handler. The web API is the ping/pong one, we discussed in the previous lesson.

Get hands-on with 1200+ tech skills courses.