Test all the units!
using Mocha, Chai and Istanbul
All my latest articles can be found at the RisingStack blog.
About TDD
TDD is the process of:
- writing a (initially) failing test case that defines a new/improved function
- write the minimal code that passes that test
- refactor
Please notice, that this is a cycle, not a thing you will only do once — you should iterate over and over your code, and add more and more tests.
But why? Why should you bother? Well, because Darth Vader says so.
But here are the real life advantages too:
- less debugging
- good unit tests can function as a documentation too
- helps designing the system — one must give some thoughts on the interfaces when writing unit tests
- can lead to more modularised and extensible code — as thinking in small units is a must, so they can be tested easily
Setting up your test environment
Prerequisites:
- Node.js project \o/
- existing package.json file
Let’s install the goodness!
npm install mocha --save-dev
npm install chai --save-dev
After this, Mocha will live under node_modules/.bin, so no need to install it globally, just add these lines to your package.json:
"scripts": {
"test": "mocha test",
}
It can be ran with npm test. This command will look for your test files under the test folder, and run them. By default, Mocha will look for an option file under test/mocha.opts — you can use it to pass additional arguments to it. For now, let’s go with this one:
--require test/setup
--reporter spec
--ui bdd
--recursive
Little explanation: with the require option Mocha can be instrumented to require node_modules, like setup scripts, the reporter option specifies how you want to see the results of the tests. The ui can change wether you want to write your tests in BDD/TDD style. I guess you already figured out what recursive does ☺
A typical output of a Mocha run using the spec reporter can be seen on the picture above. Of course, for now we have only set our testing environment, you do not have any tests to run, these pictures are just examples.
Chai will be our assertion library.
For more info on Mocha check out visionmedia.github.io/mocha, for more info on Chai take a look at chaijs.com.
Writing your test cases
Your tests should live under a directory called test. Let’s go through a basic example. We will create a module, that just multiplies the input by two:
//test/multiply.js
var multiply = require(‘../multiply’);
describe(‘Multiply module’, function () {
it(‘multiplies 3 by 2', function () {
expect(multiply(3)).to.be.eql(6);
});
});
Please note, that the test case was the first thing to do, after that comes the implementation of the module.
//multiply.js
module.exports = function multiply (num) {
return 2 * num;
};
Of course, it is only a very basic test case for a very simple module, but concept will be the same for more complex modules as well.
Also keep in mind, that when writing unit tests mock out every dependencies that the module may have — you do not want to test in the unit test how they work together, but only the behaviour of that single unit.
Code coverage with Istanbul
Code coverage it the degree to which the code of an application is tested by the test cases.
There are three basic coverage types:
- statement coverage: how many percentages of the statements was executed by the test cases?
- branch coverage: how many percentages of each control structure (like an if-else) was executed by the test cases?
- function coverage: how many percentages of the functions was called by the test cases?
Luckily you can choose from lots of tools to get your code coverage info. For now, I will show you how to setup Istanbul. Of course, you should install it first:
npm install istanbul --save-dev
The only step left is to add a new script to our package.json file to run Istanbul with Mocha.
"scripts": {
"test": "mocha test",
"coverage": "istanbul cover _mocha test --recursive -- -u exports -R spec && open coverage/lcov-report/index.html"
}
This can be run with npm run coverage, and will run your test cases and while generating a coverage report. Using this, the report will be opened in your browser — also there is a json output as well if you want to use it some way other.
Note: you should add the coverage folder to the .gitignore file
Outro
Writing unit tests is not that hard and your future self will be very grateful — so test all the things! ;)
Also, if you have any question/feedback, feel free to reach me out at @nthgergo.