Containerized Testing for Node Applications with Dockunit

This tutorial covers setting up containerized unit testing for Node applications. Containerized unit testing allows you to ensure your software works across a wide variety of platforms.

Overview

Writing and distributing Node.js applications necessitates supporting as many versions of Node.js as possible. npm, the most popular Node.js package manager, requires Node.js 0.8 or higher. Therefore to support your users, potential downloaders, or even your customers, it behooves you to test your program on Node.js versions 0.8 and up. Node.js 0.8 was released in 2012; many versions have been released since then. io.js and Node.js were combined in version 4.0.0. You have a lot of testing ground to cover!

There are a few ways to run your code in multiple versions of Node.js: n and nvm are npm packages that allow you to switch between different versions of Node.js. It’s difficult quickly switch between versions to test your code. It’s also difficult to batch run your code against a list of versions. Travis CI is a continuous integration service that allows you to run your code across multiple versions of Node.js. However, you are stuck with the versions of Node.js that they want to support, or you can use their new Docker based system which is somewhat experimental and cumbersome to operate.

Neither of these ways did the trick for me. Enter Dockunit.

Dockunit is a utility for running containerized software tests. Dockunit.io is a continuous integration service built for Dockunit. Let’s setup Dockunit to be used with our Node.js application.

Part 1: Develop a Simple Node Application (skip if you have an existing application)

We need a simple Node application to test for the purposes of this tutorial. We will write a simple app that prints out the current system time that includes one basic unit test. The code for this tutorial is available on Github.

Let’s start by creating a folder on your machine:

/test-app

Next, let’s initialize a package.json file from within the /test-app directory. In the terminal enter:

npm init

Just press enter on all the prompts. No need to specify all this information for our simple application. Next let’s create a file time.js such that our application looks like this:

This code just instantiates a Time object and prints the current time to the screen. colors is a npm package that let’s you give your terminal output some color. We need to install the npm package for this to work. In the terminal run the following command from within the /test-app directory:

This code tests up a simple unit test that instantiates a Time object and makes sure the proper instance variables are setup.

Run the following command in your terminal from the root of your project:

mocha

If you have setup your tests correctly, it should show you one test is passing.

That’s it! You now should have a simple node app with a basic unit test setup. Again, you can find all the code for this tutorial on Github.

Part 2: Setup Dockunit

We want our application to work across many different versions of Node since we will be distributing it publically. We need to be able to quickly run our tests locally across a number of Node versions. We also want our teammates and collaborators to be able to run the same tests without having to setup complex local environments. We will use Dockunit to accomplish this.

First, install Dockunit locally. In the terminal run the following command:

npm install -g dockunit

In the root of the test-app folder, create the file Dockunit.json like so:

Dockunit.json files are written in JSON which is JavaScript object notation. All Dockunit.json files contain a root level object with a property containers which holds an array of objects that each describe a test to be run in a Docker container. The idea is for containers to be different real life simulations of your software so you can see how it performs in different scenarios. Here is an example container object:

prettyName is just an easy way for you to describe your container which will be useful in build output. image refers to a Docker Hub image. Dockunit comes with a bunch of predefined images that you can use, however you can always create your own. beforeScripts allows you to run commands in the Docker container before the test command is run. testCommand is the command whose exit code will be evaluated to determine whether your software “passes” or not.

This particular Dockunit.json file describes three containers, one for Node 0.10.40, Node 0.12, and the latest version of Node. Let’s run Dockunit. In the terminal run the following command from the root of your test-app folder:

dockunit

The first time you run the command it will take a few minutes to download all the relevant Docker images. Subsequent runs will be much faster. You should see your test output for all three containers. If you are using the example application, 1 out of the 3 containers will show as passed.

What happened?

Well, in test-app/time.js we are using ES6 class style syntax which is only available in newer versions of Node. Let’s refactor our code to make it more compatible with older versions of Node. Paste the following code into test-app/time.js:

Rerun Dockunit by running the following command in your terminal from the project root:

dockunit

Now all your containers should be passing. See how easy it is test your code against multiple versions of Node? Since the images are distributable and live on Docker Hub, anyone can run Dockunit on your project without setting up a local environment.

Part 3: Setup Continuous Integration with Dockunit.io

Now that we’ve setup Dockunit for our project and pushed to Github, we can set up continuous integration on Dockunit.io so Dockunit tests are run on each pull request and push to the repository. If a pull request or push fails, a failed status will be shown on Github so we can fix our software.

That's it! You can now see the build status of your project. It will update automatically when you push to Github:

Within Github, you can see the Dockunit build status within each Pull Request:

Conclusion

In this tutorial we have created a simple Node application, setup Dockunit for local containerized unit testing, and integrated our project’s Github repository with Dockunit.io for continuous containerized integration testing. Containerized software testing is the future of assuring code integrity. Give it a try!