Mock Server
What is a Mock Server? The Quick Explanation
The short definition: A mock server is software or code that simulates the responses of a live server during testing and development.
Some more details: Mock servers are designed to mimic the responses of real servers used in a certain software system, without actually connecting to or affecting any real-world data. This is useful for testing and development because you can use the mock service to create all kinds of scenarios that might be hard or impossible to replicate with the real server, or scenarios that you want to test without risking the integrity of real data. You can configure it to return specific responses, error messages, or timeouts, depending on what you're testing for or the API you’re looking to mock.
Mock Servers vs. ‘Real’ Servers
For our purposes, a "real" server refers to a live server that's connected to an actual database or a specific service in a production environment. When you interact with a real server, it typically carries out tasks like:
- Processing requests: For instance, when you ask for a specific webpage or service, the server processes your request and sends back the relevant response.
- Managing databases: Real servers often interact with databases to retrieve, modify, or store data. For example, if you're using an online shopping app, your interactions (like browsing items, adding them to your cart, or placing an order) might involve several requests to and responses from a real server.
- Handling business logic: Servers can process data, make calculations, or execute certain actions based on business rules and logic.
In contrast, a mock server is a stand-in for a real server during testing (see also: dummy server). It doesn't interact with actual databases or services; instead, it simply mimics the behavior of a real server by providing pre-defined responses to requests. This helps isolate the system under test and provides a controlled environment for testing. It also allows you to simulate difficult scenarios such as outages, slow responses, or unexpected data, which would be difficult to ‘fake’ without affecting performance if using a live server.
Using Mock Servers in Testing
Many testing frameworks, including JUnit (Java), PyTest (Python), Mocha/Chai (JavaScript), and others, can easily use mock servers for testing purposes. These test cases interact with the mock server in the same way your application would interact with a real server, ensuring each component behaves as expected under different scenarios.
For example, in unit testing, a test case may make a request to the mock server and assert that the response is as expected. This allows you to check whether your code is correctly handling each possible response from the server.
Mock Servers in CI/CD Pipelines
In a typical Continuous Integration (CI) or Continuous Deployment (CD) pipeline, every code commit triggers a sequence of actions – such as building the project, running unit tests, integration tests, and deploying the code to a production or staging server.
Mock servers are often used in the testing stage of this pipeline. When the pipeline runs the project's tests, those tests can interact with the mock server just as they would in a developer's local environment.
This enables the CI/CD pipeline to quickly catch any issues that arise due to changes in how the application interacts with the server. Since the mock server behaves consistently, any test failures in the pipeline can be attributed to changes in the codebase, rather than variability in the server's behavior.
Setting up a Simple Mock Server in WireMock
Let's say you're developing an app that fetches user data from a server. In your tests, you might want to check how your app behaves when the server takes too long to respond, or when it returns an error message. To do this, you could set up a mock server to simulate these scenarios
Here’s how we can accomplish this using Java and the WireMock (the popular open source framework). You’ll need to download and install WireMock first. If you’d prefer to use a UI rather than write Java code, you can use WireMock Cloud.
First, we start the WireMock server:
// Start a WireMock server on port 8080
WireMockServer wireMockServer = new WireMockServer(8080);
wireMockServer.start();
Let's first simulate a scenario where the server takes too long to respond. We can instruct WireMock to delay its response by a certain amount of time. In this case, we'll use a delay of 5000 milliseconds (or 5 seconds):
wireMockServer.stubFor(get(urlEqualTo("/api/users/1"))
.willReturn(aResponse()
.withFixedDelay(5000)
.withHeader("Content-Type", "application/json")
.withStatus(200)
.withBody("{\"id\": 1, \"name\": \"John Doe\"}")));
With this setup, any tests that make a GET request to "/api/users/1" will have to wait for 5 seconds before receiving a response. You can then verify whether your app handles this delay gracefully, for example, by showing a loading indicator or timing out as expected.
Next, let's simulate a server error. We'll configure WireMock to return a 500 'Internal Server Error' status when a GET request is made to "/api/users/2":
wireMockServer.stubFor(get(urlEqualTo("/api/users/2"))
.willReturn(aResponse()
.withStatus(500)));
Now, any tests that make a GET request to "/api/users/2" will receive a server error. You can check whether your app handles this error correctly, perhaps by showing an error message to the user or attempting to retry the request.
Finally, we should stop the WireMock server at the end of our tests:
wireMockServer.stop();
You can simulate various scenarios and test how your application behaves under different conditions. You can easily modify the server's behavior to fit your testing needs, providing a flexible and powerful tool for developing robust applications.