Beliebte Suchanfragen

Cloud Native

DevOps

IT-Security

Agile Methoden

Java

|
//

Mock Server powered by Mountebank and Docker

31.5.2015 | 5 minutes of reading time

Abstract

When building applications which are dependent on other systems e.g. for business logic or data integration purposes the question of testing without these systems arrises. In a classic approach we usually mock them out on a unit test or functional test basis. But still something can break on the way through the application stack down to the network layer.

In this article we focus on a solution which provides a mock server for such a test which is performed through the stack. This way calls through an application run against a mock server and can be tested thoroughly. This allows thorough application and system end-to-end tests.

Mountebank

Mountebank is an open source tool, which provides cross-platform, multi-protocol test doubles on a network [1 ]. An application which is supposed to be tested, just needs to point to the IP or URL of a Mountebank instance instead of the real dependency. It allows to test your application through the whole application stack, as you would with traditional stubs and mocks. Supported protocols include HTTP, HTTPS, TCP and SMTP.

For this puprose it provides a DSL which can be used to configure imposter stubs to provide static or dynamic responses on requests [2 ]. These stubs’ functionality is extended by a proxy mode to record and replay calls to the original system [3 ] and a mock verification system, which allows the querying for responses of asynchronous calls[4 ].

For most cases a simple request response mock stub is enough. Such a definition for example for a HTTP mock would be defined as followed:

1{
2  "port": 8010,
3  "protocol": "http",
4  "name": "My Mock",
5  "mode": "text",
6  "stubs": [
7    {
8      "responses": [
9        {
10          headers: {
11            'Content-Type': 'text/xml'
12          },
13          body: "..."
14        }
15      ],
16      "predicates": [
17        {
18          "and": [
19            {
20              "equals": {
21                "path": "/MyService/MyOperation"
22              }
23            },
24            {
25              "contains": {
26                "body": "Mountebank"
27              }
28            }
29          ]
30        }
31      ]
32    }
33  ]
34}

It will listen on port 8010 for an HTTP call. When the predicates are met, in this cases a call to /MyService/MyOperation which contains “Mountebank” in the POST body, an HTTP response will be sent with the HTTP Content-Type “text/xml” and the body “…”.

This definition can be provided to Mountebank either by the web UI, which is accessible from port 2525, via the REST API or when the application is started.

Mock Data File Structure

When the application is started a configuration file can be sent automatically to the Mountebank instance via its REST API.

Because such a file with multiple stubs can be huge and complicated a simplification is necessary. This is provided the by integration of JavaScript EJS templating. It can be used to construct a larger mock data set from multiple files in different folders.

The root file “imposters.ejs” importing a list of mock sub folders for such a large mock data set would look like that:

1{
2  "port": 8010,
3  "protocol": "http",
4  "name": "NKD Mock",
5  "mode": "text",
6  "stubs": [
7    <% include myServiceA/imposters.ejs %>,
8    ...
9  ]
10}

Here the subfolder file “myServiceA/imposters.ejs” would specify the stubs and the responses, which could be in separate files for complexity reduction reasons:

1{
2  "responses": [
3    {
4      "inject": "<%- stringify(filename, 'myServiceA/responseA.ejs') %>"
5    }
6  ],
7  "predicates": [
8    {
9      "and": [
10        {
11          "equals": {
12            "path": "/MyService/MyOperation"
13          }
14        },
15        {
16          "contains": {
17            "body": "Mountebank"
18          }
19        }
20      ]
21    }
22  ]
23},
24{
25  "responses": [
26    {
27      "inject": "<%- stringify(filename, 'myServiceA/default.ejs') %>"
28    }
29  ],
30  "predicates": [
31    {
32      "equals": {
33        "path": "/MyService/MyOperation"
34      }
35    }
36  ]
37}

In this case we have a additional default fallback when the previous predicates are not evaluated successfully.

The response itself is returned as a Json object from a JavaScript function from the response file “myServiceA/default.ejs”:

1function() {
2  return {
3    headers: {
4    'Content-Type': 'text/xml'
5  },
6    body: "..."
7  };
8}

Docker

Docker is a Open Source technology which allows the virtualisation of maschines as isolated containers on the host system. It provides the fast and resource efficient creation of VMs by using Linux technologies such as Cgroups and Namespaces. This enables the creation of portable, reproducible and immutable infrastructures. These are a huge bonus for the creation, reproducible execution of test scenarios which include infrastructure.

Building the Mock Server

In order to build a Docker image which is pre-filled with our mock data for our mock server, we use a Docker image which has Mountebank pre-installed and is available from the Docker repository. Our Dockerfile looks like this:

1FROM                    cpoepke/mountebank-basis:latest
2 
3ADD resources/imposters /mb/
4RUN ln -s /usr/bin/nodejs /usr/bin/node
5 
6EXPOSE 2525
7EXPOSE 8010
8 
9CMD mb --configfile /mb/imposters.ejs --allowInjection

When building the Docker image, it copies our mock data from the “resources/imposters” folder into “/mb” in our new Docker image, exposes our Mountebank ports and provides a run command which loads the mock data when the container is started.

Building the Docker image is as usual:

1build --tag="my-ws-mock" .

Running the Mock Server

Now to run our mock server with already mapped ports, we just need this command:

1run -t -i -p 2525:2525 -p 8010:8010 --name='my-ws-mock' my-ws-mock

Notice: Do not to forget the port forwarding on Mac and Windows for boot2docker!

Further Work

Further work can be done by integrating the creation of this docker image and its deployment to a repository using a continuous integration/continuous deployment pipeline. From there it can be used in automated integration, acceptance, smoke or system end-to-end tests depending on your testing strategy. Even larger test scenarios are possible, where multiple different mock servers can be defined to test a distributed systems such as a Microservices based architecture by starting them when the infrastructure is initialized.

Conclusion

We have shown in this post how an external mock server with a large mock data base can be defined. This mock server can be packed by using the container technology Docker and can be further more integrated in the continuous integration/continuous deployment pipeline. This provides us with the possibility to test the whole application stack through to the network layer.

References

[ 1] http://www.mbtest.org
[ 2] http://www.mbtest.org/docs/api/stubs
[ 3] http://www.mulesoft.org/documentation/display/current/Unit+Testing
[ 4] http://www.mbtest.org/docs/api/mocks
[ 5] https://www.docker.com/whatisdocker/

|

share post

Likes

0

//

More articles in this subject area

Discover exciting further topics and let the codecentric world inspire you.

//

Gemeinsam bessere Projekte umsetzen.

Wir helfen deinem Unternehmen.

Du stehst vor einer großen IT-Herausforderung? Wir sorgen für eine maßgeschneiderte Unterstützung. Informiere dich jetzt.

Hilf uns, noch besser zu werden.

Wir sind immer auf der Suche nach neuen Talenten. Auch für dich ist die passende Stelle dabei.