alxolr's blog

the road to node.js mastery

How to separate mocha tests in multiple files

How to separate mocha tests in multiple files

Introduction

One of my latest tasks was to unit test a central module in our application; there were some tests but not as many as needed. We go for at least 75% code coverage.

The most significant issues were that the test file rapidly grew up to 2000 lines of code which is unacceptable. Maintaining large files of code is an arduous task.

We concluded that we need to separate our test suite in multiple files.

The source code for the following tutorial can be found at mocha-tutorial

Step 1. Understand mocha hooks

For this study, we are creating a small project to have a better feeling how mocha loads the before and after hooks.

Let's create a small test case with the following structure:

- hooks/
  - first/
    before-first.ts
    - second/
      before-second.ts
      some.test.ts
  before-hooks.ts

Source code for before-hooks.ts

before(() => {
  console.log('Hooks level');
});

Source code for before-first.ts

before(() => {
  console.log('First level');
});

Source code for before-second.ts

before(() => {
  console.log('Second level');
});

Source code for some.test.ts

import assert from 'assert';

describe('Some simple test', () => {
  it('should return true', () => {
    assert.strictEqual(true, true);
  });
});

After we compile and run the code with mocha ./dist --recursive we receive the following result:

Hooks level
First level
Second level
  Some simple test
    ✓ should return true


  1 passing (6ms)

We noticed that mocha supports multiple before hooks and they run first in the order of the folder structure.

This means that we can set up our system in the before hooks and use it in the child folders.

Step 2. Create a test module

The following code represents our module to be tested.

// /lib/subject.ts

import { Dependency1 } from './dependency1';
import { Dependency2 } from './dependency2';

export class Subject {
  constructor(private dep1: Dependency1, private dep2: Dependency2) { }

  public do(param: string) {
    return param;
  }
}

Dependency1 and Dependency2 are just 2 empty classes as following:

// /lib/dependency1

export class Dependency1 {
}

Step 3. Setup our test folder structure

The test folder structure will be the following

- test/
  - lib/
    - subject/
      - suites/
        first.test.ts
        second.test.ts
        third.test.ts
      index.ts
      before-subject.ts

The source code for before-subject.ts

// /test/lib/subject/before-subject.ts

import { Dependency1 } from '../../../lib/dependency1';
import { Dependency2 } from '../../../lib/dependency2';
import { Subject } from '../../../lib/subject';

before(function() {
  const dep1 = new Dependency1();
  const dep2 = new Dependency2();

  // We are attaching the subject instance to mocha this
  // We will get the subject instance during the test run
  this.subject = new Subject(dep1, dep2);
});

The source code for first.test.ts

// /test/lib/subject/suites/first.test.ts


import assert from 'assert';

export default function suite() {
  it('should return "good" when sending "good"', function() {

    // We are receiving the injected subject from the this.test.ctx
    // which are set up during the before hooks

    const result = this.test.ctx.subject.do('good');

    assert.strictEqual(result, 'good');
  });
}

So to wrap our test the source code for index.ts

// /test/lib/subject/index.ts

import first from './suites/first.test';
import second from './suites/second.test';
import third from './suites/third.test';

describe('Subject', function() {
  describe('first suite', first.bind(this));
  describe('second suite', second.bind(this));
  describe('third suite', third.bind(this));
});

When we build and run our unit tests we will receive something like:

  Subject
    first suite
      ✓ should return "good" when sending "good"
    second suite
      ✓ should return "bad" when sending "bad"
    third suite
      ✓ should return "the ugly" when sending "the ugly"


  3 passing (6ms)

Conclusions

  • Mocha supports multiple before/after hooks in child folders also.
  • We can set up our test class in before hooks by attaching to the this instance, and we will be able to extract it in it functions at this.test.ctx

If you find useful my content, you can subscribe to receive an email with the newly backed articles, or follow me on Twitter

×