When we are developing software based on microservices architectures, one of the main problems that it may arises is: how do we test one component with others?. Sometimes, one component in our application needs other component running to have the expected operation. The most simple example is a RESTful API that needs a persistence layer to save data.

In this post, I will show how docker-composer-manager can help us to create good integration tests for ensuring that this component has the correct operation. In order to illustrate examples, I will use darteaga/pets. This microservice is a simple RESTful API for managing pets which has a Mongo DB dependency for running correctly. In this case, if we want to test the API, we will need a MongoDB running. The test environment, which I will use, has mocha, chai and request as a testing tools. If you want to know more about these technologies you can access to the documentation through the links above.

First, we must install NPM dependencies

To install the test environment dependencies, you will have to execute the following command:

npm i mocha chai request --save-dev

and before install docker-composer-manager with this command:

npm i docker-composer-manager --save-dev

Files and directories

I recommend to create a directory named tests and here allocate all of the test files.

+-- src
+-- test
|   +-- 00-bootstrap.js //this file will bootstrap the env
|   +-- 01-api.test.js
|   +-- docker-compose.yaml // It will have the required components
+-- package.json

The 00-bootstrap.js contains ​the code where will be set the environment up and the global variables, that are required in the tests, will be declared.

I recommend naming all test files with the same pattern, in this case, I will name *.test.js ​in order to do its executions easier. I usually give a number ​to the name of this files in order to execute them in a given order.

Finally, you can add a new script in the package.json. This script will call mocha passing all test files.

"scripts": {
    "start": "node .",
    "test": "mocha --reporter spec --require tests/00-bootstrap tests/**/*.test.js",
    "postinstall": "bower install"
  },

Then, when you execute the following command the tests will be executed:

npm run tests

00-bootstrap.js

Here you can see how it looks the 00-bootstrap.js.

'use strict';

//set the environment to test 
process.env.NODE_ENV = "test";

//Load chai
var chai = require('chai');

//set expect to chai.expect
global.expect = chai.expect;

docker-compose.yaml

Here we will define the microservices architecture, that it is needed, using docker-compose file references. In this example, we only need a Mongo DB and we will use the official docker image of mongo library/mongo.

version: '2'
services: 
  mongo:
    image: mongo
    ports:
      - 27017:27017

01-api.test.js

This file can be more extensive and large, but, the objective is to illustrate some example of use. How it has said before, the problem is that we need a Mongo DB running to test the API. Well, Docker gives us the solution, but, how can we automate this task?. docker-composer-manager helps us to automate it.

First, we have to set the architecture of our application up with docker-composer-manager as follow:

'use strict';

//add test dependencies
var request = require('request'),
    dcManger = require('docker-composer-manager');
//add API module
var src = require('../src/pets-api');

describe('API Test', function () {
    this.timeout(30000);
    var server;

    before(done => {
        //Set the architecture up before excecuting tests.
        dcManger.dockerComposeUp(__dirname + '/docker-compose.yaml').then(out => {
            setTimeout(() => {
                //before the architecture is running, turn on the component 
                src.deploy().then(api => {
                    server = api;
                    done();
                }, done);
            }, 5000);
        }, done);
    });

    after(done => {
        //turn off the architecture after excecuting tests.
        dcManger.dockerComposeDown(__dirname + '/docker-compose.yaml').then(out => {
            //turn off the component 
            server.close();
            done();
        }, done);
    });
});

After that, you have to write your tests:

...
it('CREATE a new pet test', done => {
        var pet = {
            name: "fuffy",
            tags: ["Cat", "Lazzy"]
        };
        request.post({ url: 'http://localhost:5000/api/v1/pets', body: pet, json: true }, (err, res, body) => {
            if (err) {
                done(err);
            } else {
                done();
            }
        });
    });

    it('GET all pets test', done => {
        request.get({ url: 'http://localhost:5000/api/v1/pets', json: true }, (err, res, body) => {
            if (err) {
                done(err);
            } else {
                expect(body.length).to.be.equal(3);
                done();
            }
        });
    });
...

Now you are able to execute the integration tests running the command we have prepared in the package.json:

npm run tests