How to Mock HTTP APIs With MockServer
As the name suggests, MockServer is a powerful tool that allows developers to mock HTTP APIs, making testing much easier and more efficient. It aims to solve the problem of testing APIs that are still in development or not yet available, allowing developers to continue working without being held up by dependencies.
While there are other popular mocking tools available, such as WireMock and Pact, MockServer stands out for its focus on providing a quick and easy mock solution that’s supported in most major programming languages and technologies.
This post will cover step-by-step instructions on how to use MockServer to mock an HTTP API, as well as an overview of any limitations you might encounter. It’s important to note that while MockServer is a great tool, it may not be the best fit for every use case. This post intends to present a great use case for MockServer, but remember to evaluate for yourself and your unique scenario.
What Is MockServer?
MockServer is designed to simulate external HTTP APIs which significantly streamlines the application testing process. It stands out from other mocking tools due to its impressive range of deployment options. Just in Java, you can use it as a JUnit 4 @Rule, a JUnit 5 Test Extension, or a Spring Test Execution Listener, so MockServer can fit into a variety of workflows.
The versatility and adaptability of MockServer set it apart from its peers. No matter the environment – be it local development, Docker-enabled, or Kubernetes, MockServer likely integrates well into your infrastructure. Its compatibility with popular build tools like Maven and Grunt and the ability to be used programmatically through Java or Node.js makes it applicable in a variety of testing scenarios.
It’s an excellent choice when you want to keep things local or need a tool that can be worked directly into the code regardless of the language you’re using.
How to Mock HTTP APIs
Aiming to provide value to as many as possible, this tutorial will use one of the language-agnostic options: docker-compose. MockServer will be used to establish a mock HTTP API for a hypothetical online game platform. This platform offers a RESTful API that game developers use to fetch player statistics, update game scores, and manage in-game purchases. Our objective is to replicate this API’s behavior with MockServer, allowing us to test the client-side interactions independently, without requiring a connection to the actual game platform’s servers.
Configure Expectations Using JSON Initializer
In the MockServer ecosystem, request/response pairs are referred to as Expectations, which can be written as Java or JavaScript code, or, you can define them in a JSON file—which is what you’ll do now. This approach allows you to separate your mock definitions from your code, making them easier to maintain and reuse, especially across projects. Create an initializer.json
file in your current directory with the following content:
[
{
"httpRequest": {
"method": "GET",
"path": "/player/stats",
"queryStringParameters": {
"playerId": ["1234"]
}
},
"httpResponse": {
"statusCode": 200,
"body": "{\"playerId\": \"1234\",\"gamesPlayed\": 57,\"averageScore\": 3200,\"topScore\": 5600}",
"headers": {
"Content-Type": ["application/json"]
}
}
}
]
This JSON file declares an expectation for a GET request to /player/stats
with a playerId
query parameter. When this request is received, the server responds with a 200 status code and a JSON body containing some made-up player statistics.
Set Up MockServer Using Docker-Compose
With the expectations defined you can now spin up the MockServer using docker-compose. Docker-compose may not be strictly necessary in this case as it’s only one container, however, it helps provide a clear and approachable overview of container configurations.
Create a docker-compose.yaml
file with the following content:
version: '3'
services:
mockServer:
image: mockserver/mockserver:latest
ports:
- 1080:1080
volumes:
- ./initializer.json:/config/initializer.json
environment:
MOCKSERVER_INITIALIZATION_JSON_PATH: /config/initializer.json
This configuration exposes the MockServer on port 1080 and mounts the initializer.json
file from your current directory into the /config
directory inside the container, which the environment variable MOCKSERVER_INITIALIZATION_JSON_PATH
points to so MockServer can load your expectations from it.
To start the MockServer container, run docker-compose up -d
which will start the MockServer in the background.
Interacting With The Mock
Once MockServer is configured and running, interacting with the mock API is very similar to interacting with any other RESTful API. Given that you’ve only set up an expectation for a “GET” request to /player/stats
endpoint with a playerId
of 1234, let’s test that.
Get a response from the mock API by running:
curl "http://localhost:1080/player/stats?playerId=1234"
{"playerId": "1234","gamesPlayed": 57,"averageScore": 3200,"topScore": 5600}%
Barring any bugs, you should see a response like above, which would indicate a successful mock implementation. However, MockServer does provide a better way of verifying mock API interactions.
Verify Requests
Verification is used to ensure that the MockServer received a specific request. For instance, after running some tests, you might want to verify that your client sent a GET request to fetch player stats:
curl -v -X PUT "http://localhost:1080/mockserver/verify" -d <span class="hljs-string">'{
"httpRequest": {
"method": "GET",
"path": "/player/stats",
"queryStringParameters": {
"playerId": ["1234"]
}
},
"times": {
"atLeast": 1,
"atMost": 1,
}
}'</span>
This code verifies that the MockServer received exactly one GET request to /player/stats
for the player with id 1234
.
And there you have it! You’ve successfully utilized MockServer with docker-compose and JSON configuration to mock an HTTP API.
The Limitations of MockServer
While MockServer is a powerful tool for testing and developing applications, it’s important to be aware of its limitations. Here are some aspects you should consider when deciding if MockServer is the right solution for your project.
Limited Support For Non-HTTP Protocols
MockServer has been primarily designed to handle HTTP and HTTPS requests, which makes it a versatile tool for testing web applications. However, when it comes to non-HTTP protocols, its capabilities become limited. For example, protocols such as gRPC and WebSocket, which are widely used in real-time applications, are not supported in MockServer. This could be a significant limitation if your application heavily relies on these real-time, bidirectional communication protocols.
Furthermore, while MockServer allows for updating expectations on-the-fly, its support for real-time updates and feedback during testing is not as robust as some might wish. This becomes particularly relevant in scenarios that require rapid adjustment of expectations based on ongoing test results or changing application states.
For instance, testing a system that needs to adapt to fluctuating network conditions or user loads would necessitate a tool that can accurately simulate these real-world behaviors. Unfortunately, MockServer’s real-time adaptation capabilities are currently limited.
Possible Technical And Human Performance Overhead
MockServer does provide some basic templating and dynamic response capabilities, but these might not suffice for more complex, data-driven scenarios. For instance, if your use case involves crafting intricate responses based on specific request parameters, or if you require random data generation for chaos testing, you might find the tool’s capabilities restrictive, which may mean you need to resort to additional programming or scripting to achieve the desired level of dynamism in your responses.
Coupling this with the performance overhead that MockServer might introduce, especially when dealing with a large number of tests or high request volumes, you have a two-fold challenge. While MockServer is highly efficient, the fact that it runs as a separate external process means that it does consume additional resources. In scenarios where hundreds or even thousands of tests are run concurrently, this overhead could potentially impact the application’s performance during testing.
In fairness to MockServer, this is true for any mock or load generation tool. However, MockServer comes with few infrastructure optimizations, handing over that responsibility to you.
Limited Traffic Shaping Capabilities
One of the challenges when using MockServer is its limited traffic shaping capabilities. Traffic shaping is the process of controlling the speed, volume, and nature of network traffic. It’s a valuable technique when trying to simulate real-world network conditions for applications, such as latency, packet loss, or bandwidth limits. Unfortunately, MockServer doesn’t inherently provide these features.
While you can delay responses in MockServer to simulate network latency, the functionality doesn’t extend much beyond that. For instance, it lacks native support for simulating different network qualities, such as 3G or 4G, or varying conditions, such as congested networks.
You’d need to resort to additional tooling or potentially complex workarounds to replicate these conditions effectively. This limitation may pose challenges in accurately simulating real-world scenarios or conducting comprehensive performance testing. This is of course before mentioning how some tools are moving away from traffic shaping, favoring production traffic replication instead.
Limited Built-In Monitoring And Analytics
Monitoring and analytics are crucial aspects of API testing and development. They provide insights into the performance, usage, and potential issues of your APIs. However, MockServer provides limited built-in monitoring and analytics features, as seen with the /verify
endpoint from earlier.
While MockServer does log all interactions, including setting up expectations, matching expectations, clearing expectations, and verifying requests, these logs might not be sufficient for deeper analysis or long-term monitoring. For example, you might want to monitor the rate of specific types of requests, track response times over time, or analyze usage trends for capacity planning. These advanced analytics capabilities are not natively available in MockServer.
While you can extract some of this information from the logs, doing so can be time-consuming and might require additional tooling or processing. Without a robust, built-in analytics solution, diagnosing issues, optimizing performance, or gaining insights into your API’s usage can be more challenging.
Align the Tool With Your Use Case
In conclusion, this post has provided a comprehensive guide on how to use MockServer to mock HTTP APIs, with a focus on an intriguing example of an online game platform’s RESTful API. MockServer can be used to effectively isolate client-side interactions for testing, with minimal dependency on actual server availability. However, while MockServer is a powerful tool, it’s important to consider its limitations in simulating complex scenarios and real-world network conditions.
For instance, while MockServer does support deployment in Kubernetes, you may be overwhelmed by the additional infrastructure management it requires. Instead, you’ll want to research other possible ways of mocking APIs in Kubernetes.