

How to Test Java HTTP Client Usages (e.g. OkHttp, Apache HttpClient)
source link: https://rieckpil.de/how-to-test-java-http-client-usages-e-g-okhttp-apache-httpclient/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

How to Test Java HTTP Client Usages (e.g. OkHttp, Apache HttpClient)
First time here? Get an overview of all topics you'll find answers for on this blog here.
Fetching data via HTTP from a remote system is a task almost every application has to solve. Fortunately, there are mature Java HTTP client libraries available that are robust and have a user-friendly API. Most of the frameworks ship their own HTTP client (e.g Spring with WebClient
and RestTemplate
, Jakarta EE with the JAX-RS Client), but there are also standalone clients available: OkHttp, Apache HttpClient, Unirest, etc. When it comes to testing Java classes that use one of these clients, I often see developers trying to mock the internals of the library. With this article, you'll understand why such an approach is not beneficial and what you should do instead when writing a test that involves a Java HTTP client.
Why plain old unit tests are not enough
Most of the Java HTTP clients are instantiated with static methods. In addition, we usually chain multiple method calls or use a builder to construct the instance of the client or the HTTP request.
Even though Mockito is able to mock static method calls and with deep mocking, we could keep the stubbing setup lean, we should always remember:
Every time a mock returns a mock a fairy dies.
We end up in a mocking hell and have to mock the whole setup. With this approach, we also almost duplicate our production code as the stubbing setup has to match our usage.
While we could test conditionals e.g. behavior on non 200 HTTP responses or how our implementation handles exceptions, there is not much benefit with this approach.
A better solution for testing our Java HTTP clients would be to actually test them in action and see how they behave to different responses. This also allows us to test more niche scenarios like slow responses, different HTTP status codes, etc.
A better approach for testing HTTP client usages
Instead of heavy lifting with Mockito, we'll spawn a local web server and queue HTTP responses. We can then let our HTTP clients connect to this local server and test our code.
Whether or not we are still writing a unit test depends on your definition and scope. However, we are still testing a unit of our application in isolation. Going further, we also have to take a small overhead (time-wise) into account. Most of the time this is negligible.
The two most common libraries for this are WireMock and the MockWebServer from OkHttp. We'll use the lightweight MockWebServer
for this demo, but you can achieve the same with WireMock.
There's already an example on how to use WireMock with JUnit 5 for testing a Spring Boot application on my blog: Spring Boot Integration Tests with WireMock and JUnit 5
We include the MockWebServer
with the following Maven import:
Starting the local server and adding mocked HTTP responses is as simple as the following:
Unlike WireMock, where we stub responses for given URLs, the MockWebServer
queues every MockResponse
and returns them in order (FIFO).
When specifying the mocked HTTP response, we can set any HTTP body, status, and header. With the MockWebServer
we can even simulate slow responses using .setBodyDelay()
.
For our use case, we store a successful JSON response body inside src/test/resources/stubs
to test the happy-path.
First Java HTTP client test example: Java's HttpClient
As a first HTTP client example, we're using Java's own HttpClient
. This client is part of the JDK since Java 11 (in incubator mode since Java 9) and allows HTTP communication without any further dependency.
For demonstration purposes, we're requesting a random quote of the day from a public REST API as JSON. As the HttpClient
only provides basic converters of the HTTP response body (to e.g. String
or byte[]
) we need a library for marshaling JSON payloads.
We're going to use Jackson for this purpose. First, we'll convert the response to a Java String
and then use Jackson's ObjectMapper
to map it our RandomQuoteResponse
Java class for type-safe access of the response.
To test different behaviors of our client, later on, we're returning a default quote whenever the HTTP response code is not 200 or an exception is thrown (e.g. IOException
due to a network timeout).
A simple implementation of our use case can look like the following:
Creating the HttpRequest
is straightforward. We only have to provide the HTTP method, the URL, and an HTTP header to request JSON. Here it's important to not hard-code the full URL of the remote resource as otherwise testing this client will be difficult.
We're passing the baseUrl
as part of the public constructor and use it to construct the final URL. For production usage, we can inject this value from an environment variable or a property file (e.g use @Value
from Spring or @ConfigProperty
from MicroProfile Config).
As we create the instance of this client on our own when testing, we can then pass the URL of the local MockWebServer
.
The two test scenarios: testing a successful response and a failure (HTTP code 500) are now easy to verify.
Second Java HTTP client test example: OkHttpClient
As a second example, let's take a look at a popular Java HTTP client library: OkHttp. This is a feature-rich open-source HTTP client that I've seen in several projects.
After adding it to our project
We can implement the same behavior and fetch a random quote:
The code looks almost similar to the example in the last section. First, we instantiate a client and then create a Request
that we pass to the client as the last step.
There's also no big difference in the test for this OkHttpClient
usage:
Again, we're creating the class under test (short cut
) on our own and pass the URL of the MockWebServer
to it.
Third Java HTTP client test example: Apache HttpClient
To complete the demonstration of popular Java HTTP clients, let's use the Apache HttpClient as the last example.
The implementation for fetching a random quote is quite similar to the first example when we used Java's own HttpClient
:
The test code is exactly the same, the only difference is that we instantiate a ApacheHttpClient
as our class under test:
What about other Java HTTP clients?
But what about my fancy HTTP client library? How can I test it? I assume there are even more Java HTTP client libraries available than logging libraries…
With the client example above, we saw that there is actually no big difference when it comes to testing code that uses them. As long as we are able to configure (at least) the base URL, we can test any client with this recipe.
So it doesn't matter whether we use the JAX-RS Client, the Spring WebFlux WebClient
, the Spring RestTemplate
or your MyFancyHttpClient
, as this technique is applicable to all of them.
For both the WebClient and RestTemplate you'll find dedicated articles on my blog. If you are curious and want to know how to achieve the same with WireMock
, take a look at this Spring Boot integration test example using WireMock and JUnit 5.
Have fun testing your Java HTTP client usage,
Philip
Want to learn more about testing? Join the Testing Java Applications Email Course
- 14 Days Free E-Mail Course
- Independent of the application framework
- All participants receive the JUnit 5 & Mockito Cheat Sheet ($ 9.99)
Recommend
-
246
OkHttp See the project website for documentation and APIs. HTTP is the way modern applications network. It’s how we exchange data & media. Doing HTTP efficiently makes...
-
71
Nov 5, 2017 / GIT The multiple usages of git rebase --onto I’m not Git expert and I regularly learn...
-
11
The proper usages of Exceptions in C# ...
-
7
Artifacts using Core (25) Sort: popular | newest RideOS Android SDK Commo...
-
20
ASP.NET Core Unit Test: How to Mock HttpClient.GetStringAsync() Tuesday, May 11, 2021 China Standard Time 1 Reads
-
6
Tutorial How To Test HttpClient Requests in Angular Angular Introduction Angular’s...
-
9
Test Your .NET HttpClient Based Strongly Typed Clients Like a Boss Looking at using HttpClient Interception library to setup and create a HttpClient instance to allow for testing strongly typed client classes....
-
6
-
7
Not FoundYou just hit a route that doesn't exist... the sadness.LoginRadius empowers businesses to deliver a delightful customer experience and win customer trust. Using the LoginRadius Identity...
-
11
In part one of this series, we introduced Devise using an example app to explore modules, helpers, views, controllers, and routes. In this part, we'll explore more advanced usages of Devise, specifically the use of OmniAuth, API authenticat...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK