
When it comes to the development of modern IT systems, the issue of mocking external dependencies is always somewhere nearby. An external service may not be available at the development stage, or its functionality is developed in parallel and cannot be relied upon. This question is particularly acute at the stage of writing autotests, because you need to check not only the regular behavior of your system, but also exceptional cases: the inaccessibility of the external service, cases when the external service responds with an error, and so on.
Even if you are lucky and your product has a minimum of dependencies on external services, most likely inside it is divided into components (classics of the genre - backend / frontend), which can and should be tested separately. This means that the external dependency is already the api of a neighboring component, whose development team is not at all eager to provide you with tools for managing its state.
According to my observations, testing teams prefer to limit themselves to the most basic autotest cases, explaining this as the impossibility of redefining the behavior of the external system.
')
Mocking the external system API can solve this problem.
Usually in this place testers begin to be sad, because the previous sentence means that besides the autotests themselves they need to write a service duplicating the external system in terms of functionality, and in addition to this, it is necessary to somehow manage its state so that it can respond to the same requests differently depending on the test case study
In this article I will describe
Mountebank : a tool that allows you to quickly and very flexibly mock the API directly from autotests without having to write your web service.
Mountebank features:
- API mocking on tcp, http, https, smtp protocols;
- mocking an unlimited number of API at the same time;
- flexible redefinition of mock-API logic directly during the tests using the mountebank configuration API;
- proxying requests to the external service API, saving responses and the possibility of their subsequent use in the mock-API;
- client libraries for most programming languages ​​(JS, Python, Ruby, Java, and many others).
Concept
The idea behind mountebank is simple and ingenious: it’s not necessary to write one universal mock-API for all test cases at once, it is more efficient to override the behavior of the mock-API before each test exactly to the extent required by a specific test case.
Mountebank is a web service that runs on your test site and that has its own web API. Let's call this API configuration. The configuration API is used to tell mountebank what logic you want to put in your mock-API. After that, mountebank raises imposter - a web service that implements your mock-API. In this case, mountebank does not limit you in how often you will override the behavior of the imposter.
This means that you can redefine it literally before each test and describe exactly the logic that is needed by a specific test. And nothing more!
Installation and first mocked method
You should start with mountebank with installation. Since this is a node.js application, it is most logical to do this via npm (a pre-installed
node.js is required):
>npm install -g mountebank
If you don’t want to install node.js separately, there are
alternative ways for different platforms .
Next, run mountebank from the console:
>mb
By default, mountebank takes port 2525 and if everything is good, then we see the greeting:

It is on localhost: 2525 that the mountebank’s configuration API now hangs.
For training, we will create a simple imposter, which would implement the POST / test method and if there is JSON with the object in the request body
{ “message”: “ping” }
JSON should be sent back:
{ “message”: “pong” }
In all other cases, we want 400 status (Bad Request) to be returned.
We will communicate with mountebank'om and with imposter'ami through
Postman .
To create our imposter, we send the following request to the mountebank configuration API:

A few words about what the request to create an imposter consists of.
First, we specify the protocol by which the imposter will work and the port that it will listen to. This will be the port on which our mock-API will rise. Next comes the stubs array: rules for the imposter how to respond to a particular incoming request.
Each rule consists of predicates and responses:
- predicates describes the parameters that the incoming request must match for the imposter to react to it
- Responses describes the response that will be sent by the imposter if the incoming request matches the predicates.
Every time a request comes in for an imposter, he goes over his own rules for matching the request. If the request satisfies the predicate of the rule, an appropriate response is formed to it and the further bypass of the rules ends.
Now that we know how the imposter works, it's time to check it out.
We send the imposter a request that matches the first rule:

And we get the answer:

Now we will try to send a request not complying with the first rule, which means falling under the second:

In response, as expected, we get 400 Bad Request:

Everything is working!
Each imposter can contain an unlimited number of rules, which means that it is possible to lay a rather complex logic of behavior on various requests.
At the same time, mountebank, can hold multiple imposhers at different ports and protocols simultaneously, this makes it possible to mock several external APIs at once.
Application in autotests
Now that the mechanics of mountebank have become more or less understandable, we will try to apply it where the concept embodied in it will be fully revealed: autotests.
Imagine that we are testing a bank site, the function of displaying ATMs on a map. To implement this function, front sends a request to the server to get the coordinates of the ATMs and, having received the answer, displays them on the map.
The test of this function involves two scenarios:
- front received a list of ATMs with valid coordinates: we expect that all of them are correctly displayed on the map;
- front received a list of ATMs, but some coordinates are invalid: we expect that front displayed only ATMs with valid coordinates.
In both cases, the test page sends the same request to the backend: GET / api / points.
Without mocking the backend API, it is impossible to check both cases at all: the backend in both cases will return the same set of points not satisfying any of the cases.
Even if we write our service, which will give a certain set of data, this will allow us to check in automatic mode only one of the cases.
And now let's see how these test cases can be automated using mountebank.
For the demonstration, I will use the python +
pytest bundle (a test framework with a powerful fixture subsystem).
import pytest import requests import json from page_objects import MapPage
We start.

Voila!
Thanks to mountebank, we have directly configured the mock-API from the fixture so that it gives a certain set of points, pulled a test page that turned to the mockable method and got the points we set. Well, in the test function, we just checked that only valid points were displayed on the user's screen. Due to the possibility of pytest to parameterize the fixture, we did not even have to write two tests: both test cases are covered by one fixture and one test.
In the above example, the configuration of the mock-API took place directly through the mountebank web API. In real projects, I recommend working with mountebank at a higher level of abstraction, for which a lot of client libraries are written. For only one python, there are already three of them, I am sure,
there will be for your favorite language .
In this article, I showed only a small part of mountebank's capabilities. In addition to other basic requests for working with imposters, such powerful things as proxying requests to the external systems API, mocking at the
tcp protocol level, js-injection also remained unrevealed.
So, if you are interested in this tool - welcome to the
documentation , which, by the way, is written in a very ingenious language, match the name of the tool (mountebank - (from English) cheater).