Mock Server — save time and money during development and testing

A tool to simulate any external API and start caring only about your own

Alex Lahtarin
Billie Engineering Crew
5 min readSep 7, 2018

--

Disclaimer: diagram and original implementation by James D Bloom

© Illustration: Caterina Carraro/Billie

One of the biggest (and definitely not easiest) parts of the development is integration with the external services. Our applications communicate with the external world almost at every request. But during the development and QA process we want to minimize the impact of the external logic on the system — literally saying — make the external API behave they way we want it. The key for this is the mock server.

What is a mock server

A mock server is a standalone application that is spin next to the development system and allows other systems to send the requests to it and responds with the pre-defined set of data. In general words, this is a replacement for the real API that we want to avoid calling. The main use cases are:

  • Avoid calling to expensive 3rd party services during development;
  • Speed up the testing of the slow external services;
  • Write the manual/automated tests that assert the correct behavior of the system depending on the response from external API.

Mock server in Action

In Billie, we are using the mock server for development and testing purposes heavily. The implementation that we found the most suitable is the Mock Server — http://www.mock-server.com. In next paragraphs, we will set it up, register a mock and run the request against it.

Setting up the server

There are multiple implementations of the server depending on the environment. The easiest way to set up the server is however to spin the docker image. Instruction and source files can be found here. In the most basic way, starting the server results in just two shell commands:

docker pull jamesdbloom/mockserver
docker run -d -P jamesdbloom/mockserver

After running the Docker container, you will be able to start sending requests to the default port 1080 (or the one that was specified while running) right away.

Understanding the workflow

The flow when working with the mock server is the following:

Step 1. We have to redirect the requests that were supposed to call the external API to our mock server. In the easiest way, this can be achieved by replacing the 3rd party URL with the mock server URL in the development environment.

Step 2. Mock server receives the request and tries to understand whether it can respond to it (and if yes — with what data). This is achieved by looping through the registered requests matchers and comparing the real request with each of the registered ones. If a match is found (e.g. method, URL, and query parameters are matching) then the step 3 happens — the predefined response is returned.

Step 3. When the mock server matches the request, it will return the predefined response. This response we setup alongside with the request. We can specify each and every aspect of the response — from HTTP code to body and headers.

Let’s play!

Now, when the full picture is clear, let’s set up our first simple mock. Imagine that we need to ask some external API that accepts the German postal code about the current weather temperature.

GET http://amazing-german-weather.com/api/vi/weather?code=10969
{
“temperature”: 20.5
}

The first step — we need to set up the expectation to the same path with a postal code we want to request in our test call. Setting up the expectation means that we create a pair of request-response objects:

curl -v -X PUT "http://localhost:1080/expectation" -d '{
"httpRequest" : {
"method" : "GET",
"path" : "/api/v1/weather",
"queryStringParameters" : {
"code" : ["10969"]
}
},
"httpResponse" : {
"body" : "{\"wheather\": 20.5}",
"statusCode": 200
}}'

From this moment on, any request to http://localhost:1080/api/v1/weather with postal code 10965 will result in a response with temperature 20.5.

Now, what if the user sends a wrong postal code? Let’s set up another expectation:

curl -v -X PUT "http://localhost:1080/expectation" -d '{
"httpRequest" : {
"method" : "GET",
"path" : "/api/v1/weather",
"queryStringParameters" : {
"code" : ["50555"]
}
},
"httpResponse" : {
"statusCode": 404
}}'

From now on, any request with postal code 50555 will end up in 404 response.

The last step — forward the requests to our mock server instead of real weather API and start saving time and money.

Tips and hints

  • Add even more functionality to your tests by verifying that the mock URLs where actually called. After your tests are run, call to the verify endpoint to check that given URL has been called once (more information here):
curl -v -X PUT "http://localhost:1080/verify" -d '{
"httpRequest": {
"path": "/api/vi/weather"
},
"times": {
"count": 1,
"exact": true
}
}'
  • Clear the state of your mock server by calling to reset endpoint (more information).
  • One mock server can be used to replace multiple external API s — just prefix different APIs with different prefixes, for example: http://localhost:1080/weather-api and http://localhost:1080/time-api
  • Simultaneous tests can be easily run by different QA engineers when providing a unique header for each request. Just generate a unique value — let’s call it expectation id — add the X-Expectation-Id header to the mocks and expect it to equal to your unique expectation id. Those you link all the mocks to this unique expectation id. The last step is to send this unique key alongside with the request to the system and instruct the system to proxy it to the external calls, so the mock server will match the request with the expectation header. With this approach, even the automated tests can run in parallel using only one mock server.

Reference

Amazing Mock Server presented in this article is developed by James D Bloom and can be found here: http://www.mock-server.com

--

--