Test-Driven Development with Mocha: How to

A collection of katas with JavaScript.

Build Status Build Status Coverage Status

Test-Driven Development with Mocha: How to

A code kata is an exercise in programming which helps a programmer hone their skills through practice and repetition.

The term was probably first coined by Dave Thomas, co-author of the book The Pragmatic Programmer, in a bow to the Japanese concept of kata in the martial arts.

Katas

Setup

All project dependencies are installed and managed via npm, the Node.js package manager.

npm install
npm test

Alternatively you can use Yarn.

yarn
yarn test

Continuous Integration with travis-ci.org

Travis CI is a hosted, distributed continuous integration service used to build and test software projects hosted at GitHub.

In order to use Travis CI with your JavaScript projects you must use output on console instead of the html.

"scripts": {
  "test": "mocha ./**/*.spec.js"
},
language: node_js
node_js:
  - "12"

That’s it!

Test-driven development

Test-driven development (TDD) is a software development process that relies on the repetition of a very short development cycle:

Toolkit

Mocha is a feature-rich JavaScript test framework running on Node.js and in the browser, making asynchronous testing simple and fun. Mocha tests run serially, allowing for flexible and accurate reporting, while mapping uncaught exceptions to the correct test cases.

Chai is a BDD / TDD assertion library for node and the browser that can be delightfully paired with any javascript testing framework.

Sinon is a standalone test spies, stubs and mocks for JavaScript. Works with any unit testing framework.

Istanbul instruments your ES5 and ES2015+ JavaScript code with line counters, so that you can track how well your unit-tests exercise your codebase. The nyc command-line-client for Istanbul works well with most JavaScript testing frameworks: tap, mocha, AVA, etc.

Stryker uses one design mentality to implement mutation testing. It’s easy to use and fast to run. Stryker will only mutate your source code, making sure there are no false positives.

Example

Following an example of Test-Driven Development using Mocha and Chai for the most famous application: Hello World!

Setup is easy, just run an npm command and change few lines into your package.json.

npm install -D mocha chai
"scripts": {
  "test": "mocha ./**/*.spec.js"
},

Now you are able to run unit tests with npm test.

If you want to use ES6 syntax with import/export you will need babel also. To understand more about it, you can checkout this project, I’m using it 😄

First of all we should create a new file HelloWorld.spec.js.

Now we can start writing our first test.

//- HelloWorldSpec.js

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

describe('HelloWorld', () => {
  it('should exist.', () => {
    // given
    new HelloWorld();
  });
});

RED - Try running test and it will fail.


Create a new file HelloWorld.js.

The next step is writing some code that would cause the test to pass.

//- HelloWorld.js

function HelloWorld() {
}

module.exports = HelloWorld;

💚 GREEN - Try running test and it will pass.


Need for refactoring?


We have a green bar! Now we can write a new test.

//- HelloWorld.spec.js

...

  it('should greet() correcly.', () => {
    // given
    const helloWorld = new HelloWorld();

    // then
    expect(helloWorld.greet()).to.equal('Hello world');
  });

...

RED - Try running test and it will fail.


Now we can write some code that would cause the test to pass.

//- HelloWorld.js

...

HelloWorld.prototype.greet = function () {
  return 'Hello world';
};

💚 GREEN - Try running test and it will pass.


Need for refactoring?


🎉 Done


SPEC - HelloWorld.spec.js

//- HelloWorld.spec.js

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

describe('HelloWorld', () => {

  it('should exist.', () => {
    // given
    new HelloWorld();
  });

  it('should greet() correcly.', () => {
    // given
    const helloWorld = new HelloWorld();

    // then
    expect(helloWorld.greet()).to.equal('Hello world');
  });

});

SRC - HelloWorld.js

//- HelloWorld.js

function HelloWorld() {
}

HelloWorld.prototype.greet = function () {
  return 'Hello world';
};

module.exports = HelloWorld;

Now if we decide to refactor the application moving from prototype to class, we can do it without fear.

So, let’s do this 😎

//- HelloWorld.js

module.exports = class {
  greet() {
    return 'Hello world';
  }
}

💚 GREEN - Try running test and it will pass.

Further readings