Testing with Mocha - Part 1

Having a well-designed, working code is not enough. We need to make our system more robust and have to make sure that any change in the code will not break something else in our code. It’s highly recommended to write test cases. Mocha and Chai are great tools for doing this job, which many developers find unnecessary. I will briefly introduce these test tools in this article by showing some very basic examples.

Mocha

Mocha is a JavaScript test framework, which runs on Node.js and in the browser as well. Let’s install it first!

I will use Mocha to test code on node, so first, we need to create a folder, navigate to it in the terminal and type npm init –y, which is short for npm init --yes. (Alternatively, you can type npm init and answer the questions but they are not important in this case, so I skip them and accept the default answers.) This will create our package.json file. (Note: You must have Node.js installed on your computer, so if you haven’t done that yet, please do so.)

Once we have our package.json set up, head over to the terminal and type npm i mocha –D or npm install mocha --save-dev as these two commands are equivalent. Once the installation is complete, you should see mocha with the latest version (4.1.0 at the time of writing this) in package.json under devDependencies.

Chai

Every good test case must have at least one assertion. What is an assertion? An assertion is an expression which can evaluate to true or false. If it evaluates to true, the piece of code does what it’s supposed to do and the test passes. If it’s false, there is a bug somewhere in the code and the test fails.

Chai is a cool assertion library, which provides us with a lot of helpful tools to write strong assertions. Chai also runs on Node.js and in the browser and also works well with Mocha.

Let’s install Chai as well. Type npm i chai –D in the terminal, and the latest version of chai also should appear in the devDependecies.

Setting up the files

OK, now that we have both Mocha and Chai installed, create a folder called src, and then we create two files in the src folder, app.js and app.test.js. The file and folder names are not important, it can be anything you like. I usually put the unit test files next to the file that contains the code I want to test, and name it as FILENAME.test.js.

We will create an array and will test it using Mocha and Chai.

Let’s create our not so difficult array in app.js first:

const names = ['Alice', 'Bob', 'Carol', 'Dennis'];

We need to make the array available in the test file, so let’s export it:

module.exports = {
  names
};

So far so good, so let’s head over to app.test.js.

Mocha does not need to be required at the top of the file as running the mocha command in the terminal will run our test cases.

Chai comes with various assertion styles and methods. I will use expect throughout this article, so let’s require it:

const expect = require('chai').expect;

So from now on, whenever we call expect, we will use chai’s expect method. We also need the names array, so let’s require it as well:

const { names } = require('./app);

Writing our first test case

Everything is set up, so we can write our first test:

describe('names array', () => {
  it('should be an array with length of 4', () => {
    expect(names).to.be.an('array');
    expect(names).to.have.lengthOf(4);
  });
});

The describe block organizes the test cases, so we can put similar logic inside one describe block.

The test case starts with the it statement. The first argument is what we expect from our code, namely that we want names to be an array with four elements. The second argument is a function, in which we write our assertions.

We can then beautifully chain our expectation. First, we want names to be an array, and then we expect it to have a length of 4. It’s very straightforward, isn’t it? The cool thing is that we can use chains to make our assertions more readable. The full list of chains can be found in the Chai documentation.

Running the test

We have our first test case, let’s run the test and see if it passes. Go back to package.json and enter the following in the scripts object:

"scripts": {
  "test": "mocha src/**/*.test.js"
}

The test command in the terminal will run mocha on all files in the src folder which ends in test.js.

Now head over to the terminal and type npm test, hit enter and Mocha will run. If everything goes well and why not, you should see the test passing.

We can also see the string we entered in the description of our block of tests from describe, (names array) and the name the test case is also displayed.

However, it’s a best practice to test our test.

What? Isn’t that enough?

No. What if we accidentally write a test that always passes regardless of the code? The test will immediately lose its purpose. What’s the point of having such a test?

It’s a good idea to modify the assertion to see if the test fails this time. So change the array to object in app.test.js:

describe('names array', () => {
  it('should be an array with length of 4', () => {
    expect(names).to.be.an('object');
    expect(names).to.have.lengthOf(4);
  });
});

We expect the test to fail as names is of course an array and not an object. Run the test with npm test, and indeed, our test fails. Mocha gently warns us that something is not working as expected.

Change the other assertion as well and let’s have a look again:

describe('names array', () => {
  it('should be an array with length of 4', () => {
    expect(names).to.be.an('array');
    expect(names).to.have.lengthOf(5);
  });
});

Again, we expect our test to fail, since we have four elements in the array and not five. We can also see the expected result we entered in the assertion (5) and the actual length of the array in the terminal.

This way we can be sure that our test is valid, so any time we change something in the names array, our test will fail, hence we will be warned if a future change breaks the code.

Conclusion

Mocha is an essential tool for the Node developer. Coupled with chai (or any other assertion library) it’s a powerful way to write tests and make our system more robust. In the next article I will show you some more simple test cases.

Enjoy coding!