Unit testing HTTP calls with LocalTestServer

There are times when you’re unit testing code that is making HTTP calls to a remote server. You could be using a library such as Apache’sHttpClient or Spring’s RestTemplate to do so.

Of course, you don’t want to rely on a remote service for your unit tests. Besides the overhead involved (remember that unit test are supposed to be fast) you simply cannot rely on remote services being available during execution of your tests. You probably are also not able to completely control the response for all of your test scenarios.

Consider the following simplified example.

How would you go about writing a unit test for the ExampleHttpCall?

You could of course redesign the class in such a manner that an instance of the RestTemplate gets injected into the class:

The dependency can now be mocked giving you great control. However, this approach also incurs increased complexity due to additional configuration. Furthermore, you could end up with a lot of tedious mocking.

For this simple example using a mock probably is the way to go. But this may not always be the case. If so, another possible approach employs the use of a local test server. As it happens, the Apache HttpClient project provides a LocalTestServer in its tests artifact. If you’re using Maven you can include it by adding the following dependency:

Now you can set up the server in your unit test:

Only starting and stopping a server doesn’t get you very far, of course. So there is one more ingredient that you’ll be needing. You’ll be wanting to register one or more handlers that implement the interface org.apache.http.protocol.HttpRequestHandler, e.g.:

The HttpRequestHanlder interface will have you implement the method void handle(HttpRequest request, HttpResponse response, HttpContext context) throws HttpException, IOException;
This will method will give you full control over the HTTP response.

So for our original example a minimal unit test could look something like the following code:

That’s all that it takes to get started. From here on you can elaborate by adding test cases for every possible scenario.