unit testing javascript with mocha
Unit testing provides reassurance around your code. The point of it is to make sure the code is doing the right thing.
These are the starting point for testing any application. It will allow code testing in isolation and provide instant feedback.
Sample Code
Below is some sample code that takes two inputs and creates a formatted string based on the input. (Yes, this code could be better written in many ways)
<Code code=`module.exports = { format(firstName = ”, lastName = ”) { let string = ”; if(firstName != ”) { string = firstName; }
if(lastName != '') {
if(string.length === 0) {
string = lastName;
} else {
string = string + ' ' + lastName;
}
}
return string.toUpperCase();
} };
For the examples below I am using mocha as a testing framework and chai as an assertion library.
const mocha = require('mocha');
const assert = require('chai').assert;
const name = require('../examples/nameFormatter');
const firstName = 'Kevin';
const lastName = 'Flynn';
describe('calling name.format(firstName, lastName)', function() {
it('should return empty string when nothing is supplied', function() {
let returendName = name.format();
assert.equal(returendName, '');
});
it('should return uppercase first name when firstName is provided', function() {
let returendName = name.format(firstName);
assert.equal(returendName, 'KEVIN');
});
it('should return uppercase firstName and lastName when both are provided', function() {
let returendName = name.format(firstName, lastName);
assert.equal(returendName, 'KEVIN FLYNN');
});
});
A few things about the above;
- describe() - this is a grouping for tests
- it() - is the actual test case
- assert.equal() - is the assertion library
When we run this in command line it will produce a report. Mocha already has some nice built-in styles, this is just the standard reporting.
calling name.format(firstName, lastName)
✓ should return empty string when nothing is supplied
✓ should return uppercase first name when firstName is provided
✓ should return uppercase firstName and lastName when both are provided
Hooks
Mocha comes with built in hooks, these can be ran before()and after() a series or test, or beforeEach() and afterEach() test.
These are a great way to set-up test data for tests.
Assertions
These give language around your tests, for example, assert.equal() is the same as saying a === b.
With chai you can be more explicit with your testing, you’d also be able to assert objects.
A few examples of chai's extended assert library
- assert.isUndefined()
- assert.isOkay()
- assert.include()
- assert.isAbove()
The chai asserts documentation has a full list of all types.
You can also use messages to display a hinting error when a test fails.
assert.equal(returendName, 'KEVIN', 'Name was not equal KEVIN');
This will return ‘Name was not equal KEVIN’ if the assert fails.
Mocha has other different assertion styles as does chai. For example should.js
Code coverage
Code coverage allows you to measure how many lines, branches, functions are used while the unit tests are running.
It gives you some sign of how much of a code base is covered by unit tests.
An example of an output to html command using istanbul is below.
istanbul cover --report html _mocha tests/**
Below is a report from istanbul, it allows you to pinpoint gaps in test cases.
-------------------|----------|----------|----------|----------|----------------|
File | % Stmts | % Branch | % Funcs | % Lines |Uncovered Lines |
-------------------|----------|----------|----------|----------|----------------|
examples/ | 88.89 | 83.33 | 100 | 88.89 | |
nameFormatter.js | 88.89 | 83.33 | 100 | 88.89 | 12 |
-------------------|----------|----------|----------|----------|----------------|
All files | 88.89 | 83.33 | 100 | 88.89 | |
-------------------|----------|----------|----------|----------|----------------|
=============================== Coverage summary ===============================
Statements : 88.89% ( 8/9 )
Branches : 83.33% ( 5/6 )
Functions : 100% ( 1/1 )
Lines : 88.89% ( 8/9 )
================================================================================
In this case, I am missing a test around providing a lastName without a firstName.
These are by no means the only testing tools in JavaScript but they are a good starting point. A few other test runners
Most languages should have some form of unit testing framework e.g. PHPUnit, ScalaTest or Go.