Testing in coding is a fairly critical part of any development cycle. The idea of a good test is to catch any issues that your code may generate, from obvious bugs to edge cases. It’s something that needs considering for both back and front end development and there are various tools at a coders disposal to tackle these tasks.

Now, I’m going to hold my hands up here and say my testing mojo isn’t great. It’s something I keep trying to get right but I often don’t find myself in a position professionally where I have the time or the right kind of project to set up a decent automated test, so my skills in this area are somewhat underdeveloped. Still, that doesn’t mean I can’t take some time out to skill up (a good developer is always learning, imo) so I decided to take a look at how to set up automated testing and indeed test driven development, in Node.JS.

I’ve set up a really simple Node app which you can grab from GitHub that takes arguments from a command line, performs simple calculations based on those arguments and outputs the result. So, if you launched the app with:

app.js add 2 2

The code would ADD 2 TO 2, or 2+2, which would output 4 as the answer. Very straightforward. But to code this I took a different approach. Before jumping right into building the required functions I decided to set up a series of tests that would enssure they were returning the correct calculation.

Enter Mocha and Chai

Mmmm, mocha and chai – I love a good mocha or chai. In a cup. Of course.

These aren’t hot drinks, though; Mocha is a testing suite that runs in Node and performs a series of tests on your functions, while Chai is an assertion library – basically a tool that looks at a value and assesses whether it meets certain criteria. You can find out more about Chai here.

In your project you’ll create a folder called tests, and in that folder you’ll create a series of .js files that contain the rules for each of your tests. Ideally there will be a .js file for each module you plan on writing in your application. A typical test will:

  • Describe what module it’s testing
  • Describe each test in the module
  • Determine what it expects the outcome of the test to be

So, something like this:

describe("My lovely module", function(){
    it("returns hello world", function(){
        var hello = module.helloworld();
        expect(hello).to.equal("Hello World!);
    });
});

So in the example above, the test is getting a value returned from a module called helloworld() and checks to see if the value it gets is “Hello World!”; if it is, the test passes. If it’s not, the test fails. That’s the essence of the Mocha/Chai combo, where Mocha handles the running of the tests and Chai gives you that nice, plain English expect(x).to.equal(y) assertion checking.

So, I started by creating my project, installing these two dependencies and setting up a simple test (I decided to call the project sum-it):

mkdir sum-it
cd sum-it
npm init
npm i --save-dev mocha chai
touch test/sum-it.js

That creates my basic, empty test file. We can run this by typing:

mocha --reporter spec

…or we can add an entry into our package.json:

"test": "mocha --reporter spec"

…which will allow us to run the test simply by typing npm run test.

If we do that now the whole thing will error because, well… the test doesn’t really do ANYTHING.

So, we need to define the tests.

I knew my sum-it module needed to have 4 basic functions – add, subtract, multiply and divide and that each of those would take in two numbers and return the result. Firstly I needed to include these modules (remember, I’ve not written them yet) and then define the tests for them. Using the basic Mocha/Chai layout, these are the resulting tests:

var expect = require('chai').expect;
var sumit = require('../app/sum-it');

describe("Sum It Calculator", function(){
    it("adds the numbers", function(){
        var answer = sumit.add(2, 2);
        expect(answer).to.equal(4);
    });
    it("subtracts the numbers", function(){
        var answer = sumit.subtract(4, 2);
        expect(answer).to.equal(2);
    });
    it("multiplies the numbers", function(){
        var answer = sumit.multiply(2, 3);
        expect(answer).to.equal(6);
    });
    it("divides the numbers", function(){
        var answer = sumit.divide(6, 2);
        expect(answer).to.equal(3);
    });
});

That basic test loads in Chai and the sum-it module, sets up four simple tests and checks to see if the functions are doing what they should.

But, those functions still don’t exist, so let’s create them.

Adding in the functionality

Let’s add in our empty module file:

touch app/sum-it.js

…and put some flesh on the bones of those functions:

exports.add = function(num1, num2) {
    return num1+num2;
}

exports.subtract = function(num1, num2){
    return num1-num2;
}

exports.divide = function(num1, num2){
    return num1/num2;
}

exports.multiply = function(num1, num2){
    return num1*num2;
}

One fun thing I learned through this exercise is the exports method you see used above. That allows us to define this file as a module, something we can include elsewhere and run the functions from. You can see it in the test above where we define var sumit = require(‘../app/sum-it’) and run the individual methods of the module with, for example, var answer = sumit.multiply(2, 3).

So, now we have our module set up, running npm run test on the command line will fire off Mocha, check all our functions and tell us if they’re behaving themselves. Cool stuff!

Bringing it all together – and taking it further

In the repo for this code on GitHub I’ve also built an app.js file that takes those command line arguments and fires off the methods as requested:

var sumit = require('./app/sum-it');
var args = process.argv.slice(2);

var type = args[0];
var num1 = parseInt(args[1]);
var num2 = parseInt(args[2]);

switch(type){
    case 'add':
        console.log(sumit.add(num1, num2));
        break;
    case 'subtract':
        console.log(sumit.subtract(num1, num2));
        break;
    case 'multiply':
        console.log(sumit.multiply(num1, num2));
        break;
    case 'divide':
        console.log(sumit.divide(num1, num2));
        break;
    default:
        console.log('Unknown type');
}

This all works great, but there’s more that could be done here – there’s an assumption that all the the arguments are as we expect them to be, but we could set up a function to check that before running the sum-it module and, by proxy, we can set up another Mocha test to make sure THAT function is behaving as it should.

Automated testing is cool – it makes you think more about the application you’re about to write, how the user is going to interact with it and how it’s going to interact with itself. It’s not something I have a huge opportunity to delve into professionally, but it’s definitely something I’m going to be introducing a lot more into my personal projects going forward.

As always, if you found any aspects of this article helpful, or if you have anything to add to what I’ve written here, please feel free to shout up in the comments!