How to stub requests to remote hosts with Go

Roman Budnikov
ITNEXT
Published in
2 min readMay 23, 2018

--

When creating a package with a client for some API, it’s critical to cover it with tests, especially if you want to put this package on GitHub for public usage, since the bug that got into the new version can cause deplorable consequences for projects that use it in production environments. After making the package public it’s your job to track its reliability and compatibility to make it usable for others.

Testing helps code maintainability, so when other users create pull requests with changes they make, you will always see if something is broken, and be sure that the code is still reliable, especially when you’re using some CI tool with GitHub integration like Travis, Semaphore or Jenkins.

Recently I was looking through various packages that implement clients for APIs and noticed the lack of tests in them, even though such code is easy to test by stubbing requests to the remote host. So I decided to share how I test my clients.

The code above defines a client that gives the ability to receive a list of users from the remote server, the request occurs through http.Client and by redefining itsTransport property with custom http.Transport we can redirect all requests that the client makes to another fake server, which we can create using the httptest.NewServer factory and return the responses we need.

The function above receives http.Handler interface as an argument in which we can write response body, set a status code, or anything else we are expecting from the remote host - we even can check request that we send. In the end, the function returns http.Client with redefined Transport, and a teardown function, which will stop the fake server, launched previously. Thus, we have the ability to write some test with the stubbed request.

Since our library will be used in other packages, it will be also good to give the ability to change the httpClient property by other packages, as it may be used in integration tests, for example, if our client will be injected as a dependency. You may do it by simply making httpClient *http.Client property public by renaming it to HTTPClient *http.Client, or by adding the func(cli *Client) SetHTTPClient(httpClient *http.Client) method for the client, but personally I prefer to use functional options as it’s a very powerful tool.

The full example can be found on GitHub.

--

--