A few months ago, we started a project with a Node.js backend. During this project we learned how to write clean and efficient tests, and we decided to write about it.

In this first part we will present the tools we used to test our application and why they are great. We will show you examples of Node.js tests, but the libraries can be used to test both your front and backend code. All the examples in this article can be found in this repository: https://github.com/tib-tib/demo-js-tests-part-1.

## Prerequisites

You must have Node.js and npm installed. To do so, you can follow the npm documentation.

## Let’s write a JavaScript unit test

What might a test look like when you don’t use any framework or library? Let’s take for example a function that computes the square of a given number:

```
module.exports = {
square: function(a) {
return a*a;
}
};
```

We assume that this function is in the file `/workspace/math.js`

. You can write a test in the file `/workspace/math.test.js`

. Since a test file is just a regular JavaScript file, you can name it as you wish though it is a good practice to use naming conventions. To check the behavior of the `square`

function, we can use the different methods provided in the assert module available in Node.js.

```
var assert = require('assert');
var math = require('./math');
assert.equal(math.square(3), 9);
```

To launch the test, run: `node /workspace/math.test.js`

. There is no output, that means the test succeeded because assert only provides information about the first failure. If you want a specific message you have to provide one in the argument list:

```
var assert = require('assert');
var math = require('./math');
assert.equal(math.square(2), 4, 'square of 2 is 4');
assert.equal(math.square(3), 9, 'square of 3 is 9');
```

If you make a mistake in your `square`

function – for instance `return a+a;`

instead of `return a*a;`

– and launch the test, you will now see an error:

```
assert.js:86
throw new assert.AssertionError({
^
AssertionError: square of 3 is 9
at Object.<anonymous> (/workspace/math.test.js:5:8)
at Module._compile (module.js:460:26)
at Object.Module._extensions..js (module.js:478:10)
at Module.load (module.js:355:32)
at Function.Module._load (module.js:310:12)
at Function.Module.runMain (module.js:501:10)
at startup (node.js:129:16)
at node.js:814:3
```

We can see that our test failed, but we don’t have any information about why it did.

## How to have clearer output and organized tests?

Let’s now try Mocha. Mocha is a framework to run tests serially in an asynchronous environment. In your workspace, install it with the following command:

```
npm install mocha
```

Then, we have to change our test file a little bit to use Mocha’s features. Let’s create the file `/workspace/test/math.js`

:

```
var assert = require('assert');
var math = require('../math');
describe('square', function() {
it('should return the square of given numbers', function() {
assert.equal(math.square(2), 4);
assert.equal(math.square(3), 9);
});
});
```

By default, Mocha will launch all JavaScript files located in a `test`

directory in your workspace. This is great because we just have to run `./node_modules/.bin/mocha`

to handle several test files. Another benefit is that we have some output that describes our whole application:

```
square
✓ should return the square of given numbers
1 passing (8ms)
```

In case of failure we also have a much clearer output:

```
square
1) should return the square of given numbers
0 passing (18ms)
1 failing
1) square should return the square of given numbers:
AssertionError: 6 == 9
+ expected - actual
-6
+9
at Context.<anonymous> (test/math.js:7:16)
```

We can see the tests that fail at a glance and then we have the detail of the failures. We notice that the expected and actual values are displayed, which is convenient to help us find our bug(s). Plus, we don’t have the assertion stack trace anymore, as it does not provide useful information.

Moreover, mocha allows us to have a clean and organized test structure. With `describe`

you can literally describe what you are testing, and with the `it`

function you can tell explicitly what behavior your function should have.

Now that we have a proper test organization, we can focus on our assertions. Indeed, they lack readability.

## Write assertions like you write sentences

Chai is an assertion library that helps improving the readability of your tests in two ways. First, you can use more semantic functions like `lengthOf`

, `below`

or `within`

in your assertions. Second, it provides `expect`

and `should`

interfaces in order to have a more human friendly syntax in our assertions. For instance, thanks to Chai you can write the following assertions:

```
math.square(3).should.be.above(3);
math.square(3).should.be.within(6, 12);
math.square(3).should.be.below(10);
```

Let’s go back to our previous example. You can install chai with the following command:

`npm install chai`

With chai, our `workspace/test/math.js`

will now look like:

```
var should = require('chai').should();
var math = require('../math');
describe('square', function() {
it('should return the square of given numbers', function() {
math.square(2).should.equal(4);
math.square(3).should.equal(9);
});
});
```

And the output is a bit different in case of failure:

```
# Output with mocha and assert
AssertionError: 6 == 9
# Output with mocha and chai
AssertionError: expected 6 to equal 9
```

As of now we have everything we need to test a JavaScript file. The tests we write are easy to read and their output provides useful information in case of success as well as in case of failure. However, our `square`

function had very few logic. What will happen if we want to test a function depending on other services?

## How to handle function dependencies in your tests?

Let’s add another service, called `equation.js`

, in our workspace. It will contain a `discriminant`

function, that uses the `square`

function defined in the service above.

```
var math = require('./math');
module.exports = {
discriminant: function(a, b, c) {
return math.square(b) - 4*a*c;
}
};
```

Then, let’s write a test of `discriminant`

in `/workspace/test/equation.js`

. This test looks like the test of `square`

:

```
var should = require('chai').should();
var equation = require('../equation');
describe('discriminant', function() {
it('should return the discriminant of given numbers', function() {
equation.discriminant(3, 2, -5).should.equal(64);
equation.discriminant(3, 11, 7).should.equal(37);
});
});
```

As we already said, when we launch the tests with mocha (`./node_modules/.bin/mocha`

) all the files in `test`

are used. We now have the following output:

```
discriminant
✓ should return the discriminant of given numbers
square
✓ should return the square of given numbers
2 passing (14ms)
```

Our two methods are tested. That’s great!

Let’s break `square`

and see what happens. As before we replace `a*a`

by `a+a`

and here is the test result:

```
discriminant
1) should return the discriminant of given numbers
square
2) should return the square of given numbers
0 passing (20ms)
2 failing
1) discriminant should return the discriminant of given numbers:
AssertionError: expected -62 to equal 37
+ expected - actual
--62
+37
at Context.<anonymous> (test/equation.js:7:48)
2) square should return the square of given numbers:
AssertionError: expected 6 to equal 9
+ expected - actual
-6
+9
at Context.<anonymous> (test/math.js:7:31)
```

The test of `square`

fails which is the expected behavior but the test of `discriminant`

also fails which means we did not write a **unit** test. The first consequence is that we don’t know where our code is broken. Is it `square`

or `discriminant`

that we have to fix?

To unit test the `discriminant`

function, we have to “stub” the `square`

function, that is to say we have to fake its behavior so that the test of the `discriminant`

does not depend on a function of another service. We can do this with Sinon. You can install it with the following command:

`npm install sinon`

Then, we can modify the test file `/workspace/test/equation.js`

:

```
var should = require('chai').should();
var sinon = require('sinon');
var equation = require('../equation');
var math = require('../math');
var stub;
describe('discriminant', function() {
before(function() {
stub = sinon.stub(math, 'square').returns(4);
});
after(function () {
stub.restore();
});
it('should return the discriminant', function() {
equation.discriminant(3, 2, -5).should.equal(64);
equation.discriminant(3, 11, 7).should.equal(-80);
});
});
```

You see two functions `before`

and `after`

. These functions define what to do before and after launching the tests. Here, we initialize the stub in the `before`

function, and we restore the initial behavior of `square`

in the `after`

function. After defining a stub, it is very important to restore it, because otherwise the stub will be active in following tests, and thus will break them.

The stub allows us to define a fake return value for the `square`

function. It means that whenever this function is called, it will return the value `25`

. As a consequence, when we call the `discriminant`

function with the `a`

, `b`

and `c`

parameters, the `b`

value won’t be used because the stub returns a specific value.

Now if `square`

is broken, we have the following output:

```
discriminant
✓ should return the discriminant
square
1) should return the square of given numbers
1 passing (28ms)
1 failing
1) square should return the square of given numbers:
AssertionError: expected 6 to equal 9
+ expected - actual
-6
+9
at Context.<anonymous> (test/math.js:7:31)
```

The test of `discrimant`

is ok which is what we want since there is no error in the `discrimant`

function. The test of `square`

is failing which gives us a good idea of where we made a mistake in our code.

The stub allows us to isolate the logic of the `discriminant`

function, and that’s why Sinon is very useful.

## What’s next?

Now that you understand the purpose of each library of the Mocha-Sinon-Chai stack, it is time to write some more complex tests. It will be the subject of the second part of our tutorial, in which you will learn about sandboxes, tests on functions using callbacks, or using promises among many other things. Be ready!

You liked this article? You'd probably be a good match for our ever-growing tech team at Theodo.