Using a mock server is a popular method of working around these limitations and realities, allowing you to test web server assets against specific requests, ensuring that your response data matches the expected outcome.
Today, we’re going to look at a powerful solution for Python clients in the form of MockServer. We’ll walk through the tool’s basics and learn how to use it for your own testing.
It’s important to note that if you need to capture and replay real-world traffic for your tests rather than handcraft every mock, Speedscale is a solid option to be aware of. It automatically records production calls and generates mocks, helping you validate how your APIs behave under real-life load conditions.
Introduction to MockServer
Python MockServer is a tool designed to simulate or “mock” servers during your software testing. In essence, MockServer allows developers to test the interactions between their applications, external services, and APIs without having to actually point to a real system. Using HTTP or HTTPS, you can test your system utilizing mocked server resources, allowing you to control the entire test flow and ensure more predictable, reliable, and efficient testing.
MockServer is great for matching requests against the expectations in configuration, allowing developers to see whether or not the system is behaving as expected. This, paired with dynamic port forwarding, web proxying, and HTTPS tunneling proxying, allows you to create highly variable and powerful solutions to mock dependencies, validate request flows, isolate services and applications, and much more!
Understanding the MockServer Philosophy
MockServer takes a pretty opinionated view of testing, and as such, it’s helpful to understand – and adopt – the overall mock server philosophy.
Firstly, tests should be readable and simple to understand. They should be repeatable and deployable and should be decoupled from external dependencies. MockServer is built to decouple this relationship, allowing for isolated testing free from network or external service issues.
Additionally, MockServer should be configured for the given test. While it can work straight out of the box, MocksMockServererver allows you to configure your specific tests – you should take advantage of this to ensure that your testing systems are built for the specific aspect being tested!
MockServer is also designed to be used in a test-first or contract-first paradigm. In other words, testing should be done early on and built into the system development process. Parallel development is a big goal for MockServer, so ensure that you are supporting collaborative testing and being very transparent with where MockServer is running, how it is configured, and how it can be used internally through substantive documentation.
Setting Up MockServer
There are a wide variety of ways you can get MockServer running, including as a:
- Java dependency for JavaScript use cases;
- Docker container for highly portable containerized tests;
- Helm chart for Kubernetes;
- Executable jar;
- Homebrew package;
- Maven plugin;
- npm plugin;
- Grunt plugin; and
- Deployable WAR.
For the purposes of this tutorial, we are going to leverage Docker to install and configure Mockserver.
Docker is a great containerized solution that allows you to rapidly create modular components and systems – for our efforts with MockServer; this will also allow us to have more significant control over the resourcing and environmental variables of the server itself.
Install and Run MockServer Image
Within docker, you can use the following command to set up and pull the MockServer Docker image:
docker pull mockserver/mockserver
The MockServer documentation makes a note here that this isn’t entirely necessary as the image gets pulled by default if you don’t have it when you use the run command; that being said, being verbose and direct will go a long way towards ensuring you have the right build and infrastructure to get your MockServer journey off on the right foot.
Now that you have the image, you’ll run it using the Docker run command:
docker run -d –rm -P mockserver/mockserver
This will map all ports to dynamically allocated ports and launch the MockServer container. From here, you can configure your port mapping utilizing the -p command as follows:
docker run -d –rm -p <serverPort>:1080 mockserver/mockserver
To make sure that MockServer is running properly, you can simply visit http://localhost:1080. You should now be able to use MockServer!
Using the MockServer Python Client
The mockserver-client Python package provides a simple interface for interacting with MockServer programmatically. You can install the package using pip as follows:
pip install mockserver-client
From here, you’ll need to set up a mock endpoint. You can do this by creating expectations. An expectation allows you to map certain requests and functions into a given flow, mocking the functionality of a server through Mock-server natively. It’s typically composed of a few parts – for example, an expectation type called request matcher would look for the following:
- request matcher – a variable that states what requests should be matched to the expectation; and
- action – the specific action that should be taken against that request.
You can start to model more complex requests by using optional variables, such as:
- times – how many times that action should be taken against the expectation registered in the request matcher;
- timeToLive – the lifetime of the expectation, allowing you to set a time limit in how long the expectation will be used and accessible;
- priority – the priority of the expectation, allowing you to layer other expectations together and pass mimicked object variables to make for a prioritized data flow that mimics more complex server interactions; and
- id – a variable used to track expectations and update existing ones when needed.
As an example, let’s build a request expectation for the GET method. This would look as follows:
from mockserver_client.mockserver_client import MockServerClient
# Connect to MockServer
client = MockServerClient(“http://localhost:1080”)
# Create a mock expectation
client.expect(
request={
“method”: “GET”,
“path”: “/api/example”,
},
response={
“statusCode”: 200,
“body”: “{\”message\”: \”Hello, MockServer!\”}”
}
)
print(“Mock endpoint created at /api/example”)
Now, any GET request to http://localhost:1080/api/example will return the predefined response of 200, indicating a valid request, and the text string “Hello, MockServer!”. While this is a very simple example, you can see how layering these active expectations along with the priority value could mimic more complex interactions, especially if paired with conditional logic inside of your core API that is interacting with the Mock Server.
Testing External APIs with MockServer
Now that you have your MockServer instance set up, you can go a step further and start testing external APIs. External APIs, especially those that are unreliable, can often be a huge barrier to API testing – they can hamper efforts to develop and iterate, which can be frustrating, especially if you really only need a small amount of data or context from that API.
For this purpose, MockServer is an excellent option. For instance, let’s assume that you have an external service that you are testing against. Instead of using live data and depending on a potentially unreliable third-party service, you can simply mock that data as follows:
# External API
client.expect(
request={
“method”: “POST”,
“path”: “/external/api”,
“body”: “{\”key\”: \”value\”}”
},
response={
“statusCode”: 200,
“body”: “{\”message\”: \”Hello, MockServer!\”}”
}
)
print(“200 – Service is Live”)
If you then want to test that same service as if it failed, you can update the status code and return a bad gateway warning:
# External API
client.expect(
request={
“method”: “POST”,
“path”: “/external/api”,
“body”: “{\”key\”: \”value\”}”
},
response={
“statusCode”: 502,
“body”: “{\”error\”: \”Bad Gateway\”}”
}
)
response = requests.post(“http://localhost:1080/external/api”, json={“key”: “value”})
assert response.status_code == 502
assert response.json()[“error”] == “Bad Gateway”
This allows you to test both the success and failure state of the external service, which is a significant amount of flexibility. You can even layer these responses, providing more complex interactions such as mocked data for content type states or external variables like weather, time validation, etc.
Advanced MockServer Techniques
MockServer isn’t just a simple service solution – it actually has some relatively complex functions that can be used for more advanced iteration. These include:
- Stubbing: Create mock responses for specific API requests, allowing you to simulate various API behaviors without relying on external services.
- Resetting: Reset MockServer to its initial state, clearing all active stubs, expectations, and recorded requests, ensuring a clean slate for new tests.
- Verifying: Check if specific requests were received by MockServer, enabling you to validate that your application is sending the correct API requests.
- Mocking a Form Post: Simulate form submissions by mocking requests with application/x-www-form-urlencodedpayloads, useful for testing traditional form-based APIs.
- Returning JSON: Configure MockServer to return JSON responses, ensuring compatibility with modern APIs that use JSON as their primary data format.
- Expecting JSON: Define expectations for incoming requests that import JSON bodies, allowing MockServer to match requests based on their structure and content.
- Dynamic Responses: Customize responses based on incoming request attributes (e.g., query parameters or headers), enabling running tests with more realistic and flexible frameworks and limitations.
- Request Verification: Validate that the application is sending the expected requests with precise parameters, headers, and payloads.
- Delays and Errors: Simulate network latency or server-side errors, such as timeouts or HTTP status codes, to test how your application handles real-world failure scenarios.
Adding a delay is a great example of how simple it is to build more complex simulations in MockServer. To add a delay, you simply need to use the delay variable as follows:
client.expect(
request={
“method”: “GET”,
“path”: “/delayed/response”
},
response={
“statusCode”: 200,
“body”: “{\”message\”: \”Delayed Response\”}”,
“delay”: {
“timeUnit”: “SECONDS”,
“value”: 2
}
}
)
This simulates a 2-second delay for your request. This is exceptionally useful when trying to validate error handling and fail states, as 2-second delays are long enough to impact a service but not so long as to be a straight failure – in other words, it represents a degradation of service, not a complete drop of service.
You can also use MockServer as an HTTP proxy. In this way, you can utilize MockServer to test the HTTP Client and the HTTP request, deploying your server as a verifying request engine. In order to do this, you can pass requests through MockServer and into the mocked dependencies to analyze the system as so:
Once you have generated enough information from this “record mode,” you can then use MockServer as a different type of proxy, validating and verifying the requests against the original value and expected response:
When it comes to creating dynamic or highly realistic test environments, Speedscale takes mocking a step further by recording actual API traffic. This lets you replay authentic scenarios, including edge cases and performance bottlenecks, ensuring your tests are as close to real-world conditions as possible.
How Is Speedscale Different from MockServer?
While MockServer is excellent for creating custom request-response mocks by hand or via configuration, Speedscale goes further by automatically capturing real-world production traffic and turning it into tests. This approach removes the guesswork of manually creating or updating mocks, ensures your tests mirror actual user behaviors, and helps to surface performance bottlenecks earlier. If you’re looking for a more scalable and automated solution over MockServer, Speedscale provides a data-driven alternative to traditional mock servers, helping teams accelerate development and testing cycles.
Conclusion
MockServer is a versatile and powerful tool for API testing, enabling developers to simulate APIs, handle edge cases, and ensure robust application behavior. It uses a very simple logical framework to simulate a wide variety of situations and use cases. By integrating MockServer into your Python projects, you can enhance your testing process, giving you substantially more control over your testing environment and iterative development efforts.
Looking to expand your API testing strategy? [Check out Speedscale and discover the benefits of automated traffic replay, performance visibility, and more. Give Speedscale a try and see how it can elevate your mock testing workflow beyond the capabilities of MockServer. For a 14-day free trial, you can start here!