NodeJS Boilerplate with Unit Testing - #1
Tags: node, dependencyinjection, unittesting, express
Published: 2019-12-30 17:26:06

---
title: NodeJS Boilerplate with Unit Testing - #1
published: true
description: Build application with Express Framework, Unit testing for every layer and Dependency Injection Pattern
tags: #nodejs #dependencyinjection #unittesting #express
---

## Introduction
Have we ever made a backend application from scratch. what programming language will be used, what about the performance. is there a lot of community to support it. and several other considerations. I will share a tutorial on how to create a boilerplate for a backend application using **Javascript (NodeJS runtime)** with Express Framework, how to manage dependencies between layers. and unit testing implementation with **chai, sinon and mocha**

## Pre-requisites!
* [node.js] - runtime environment javascript
* [ES6] What is Class, Arrow function in  [ECMA SCRIPT 2016] 
* [Unit Testing] What is unit testing

## Folder Structure
```javascript
.
├── .env
├── .eslintrc.js
├── .gitignore
├── config
│   └── database.js
├── package-lock.json
├── package.json
├── src
│   ├── MainApplication.js
│   ├── common
│   │   ├── middlewares
│   │   │   ├── index.js
│   │   │   └── validateSchema.js
│   │   └── repositories
│   │       ├── baseRepository.js
│   │       └── index.js
│   ├── index.js
│   ├── role
│   └── user
│       ├── userController.js
│       ├── userDependencies.js
│       ├── userModel.js
│       ├── userRepository.js
│       ├── userSchema.js
│       └── userService.js
└── test
    ├── MainApplication.test.js
    ├── common
    │   ├── middlewares
    │   │   └── validateSchema.test.js
    │   └── repositories
    │       └── baseRepository.test.js
    ├── fixtures
    │   ├── index.js
    │   ├── queryRequest.js
    │   └── userController.js
    ├── setup.js
    └── user
        ├── userController.test.js
        ├── userDependencies.test.js
        └── userService.test.js

13 directories, 28 files
```

# Development
### Installation
Iniatiate project
```
$ npm init
```
The script will created `package.json` file. lets install dev dependecies
```
npm install chai mocha nyc sinon sinon-chai --save-dev
```
Version of dependencies maybe different with this tutorial. but its does not matter.
 
```javascript
{
  "name": "nodejs_platform",
  "version": "0.0.1",
  "description": "NODEJS PLATFORM",
  "main": "index.js",
  "scripts": {
    "start": "node src",
    "lint": "eslint src test",
    "test": "nyc mocha --recursive",
    "test:coverage": "nyc report --reporter=lcov | npm run test"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "body-parser": "^1.19.0",
    "express": "^4.17.1",
    "joi": "^14.3.1",
    "lodash": "^4.17.15",
    "mysql2": "^2.1.0",
    "p-iteration": "^1.1.8",
    "sequelize": "^5.21.3"
  },
  "devDependencies": {
    "chai": "^4.2.0",
    "eslint": "^6.8.0",
    "eslint-config-airbnb-base": "^14.0.0",
    "eslint-plugin-import": "^2.19.1",
    "mocha": "^6.2.2",
    "nyc": "^15.0.0",
    "sinon": "^8.0.0",
    "sinon-chai": "^3.3.0"
  },
  "mocha": {
    "globals": "global",
    "require": "test/setup.js"
  },
  "nyc": {
    "all": true,
    "include": [
      "src/**/*.js"
    ],
    "exclude": [
      "src/index.js"
    ]
  }
}

```
### Unit Testing
create `user.service.test` file inside **test/user/**. see folder structure
```javascript
const sinon = require('sinon');

const UserService = require('../../src/user/userService');

describe('User Service', () => {
  const sandbox = sinon.createSandbox();
  let props;
  let userService;

  beforeEach(() => {
    props = {
      userRepository: {
        get: sandbox.stub(),
        filterAndSort: sandbox.stub(),
      },
    };

    userService = new UserService(props);
  });

  afterEach(() => {
    sandbox.restore();
  });

  describe('#create', () => {
    it('should return user when create user is successfully', () => {
      const expectedUser = {
        userName: 'bob',
        email: 'bob@sit.com',
      };

      const result = userService.create();

      expect(result).to.deep.equal(expectedUser);
    });
  });

  describe('#getById', () => {
    it('should call get userRepository with expected params', async () => {
      const id = 'USR001';
      const expectedParam = {
        id,
      };

      await userService.getById(id);

      expect(props.userRepository.get).to.calledWith(expectedParam);
    });
  });

  describe('#filterAndSort', () => {
    it('should call filterAndSort userRepository with expected params', async () => {
      const expectedParam = {
        filters: [
          {
            key: 'email',
            operator: 'LIKE',
            value: '@gmail',
          },
        ],
        sorts: [
          {
            key: 'email',
            order: 'DESC',
          },
        ],
        page: {
          limit: 10,
          offset: 0,
        },
      };

      await userService.filterAndSort(expectedParam);

      expect(props.userRepository.filterAndSort).to.calledWith(expectedParam);
    });
  });
});

```
### Unit Testing Description
**Set up dependency module for unit test**
```javascript
const { expect, use } = require('chai');
const sinon = require('sinon');
const sinonChai = require('sinon-chai');

const UserService = require('../../src/user/user.service');

use(sinonChai);
```
**Chai** : a BDD / TDD assertion library for node and the browser that can be delightfully paired with any javascript testing framework
**Sinon** : Standalone and test framework agnostic JavaScript test spies, stubs and mocks
**Sinon-Chai** : provides a set of custom assertions for using the Sinon.JS like "to.have.been.calledWith"

**Test Setup environment** 
```javascript
const sandbox = sinon.createSandbox();
  let props;
  let userService;

  beforeEach(() => {
    props = {
      userRepository: {
        get: sandbox.stub(),
      },
    };

    userService = new UserService(props);
  });

  afterEach(() => {
    sandbox.restore();
  });
```
**beforeEach** : runs before every Runnable instance;
**props** : properties needed for user service 
**sandbox.stub()** : Override an object’s property for the test and mocking result function
**sandbox.restore()** : Restores all fakes created through sandbox.
**afterEach**: runs after every Runnable instance;

**Create test case #1** 
```javascript
describe('#create', () => {
    it('should return user when create user is successfully', () => {
      const expectedUser = {
        userName: 'bob',
        email: 'bob@sit.com',
      };                                            // Arrange

      const result = userService.create();          // Action

      expect(result).to.deep.equal(expectedUser);   // Assert
    });
  });
```
Unit test anatomy [AAA]: 
**Arrange** : everything we need to run the experiment. you may need to seed an object with some variable values or init callback function
**Action** : represents the star of the unit testing show. we invoke the create method and capture the result.
**Assert** : something represents the essence of testing.
> Better One Assert Per Test Method

**Create test case #2** 
```javascript
describe('#getById', () => {
    it('should call get userRepository with expected params', async () => {
      const id = 'userId';
      const expectedParam = {
        id,
      };

      await userService.getById(id);

      expect(props.userRepository.get).to.calledWith(expectedParam);
    });
  });
```
unit testing will be on every layer. for `getById` we only need to make sure that this function calls get userRepository with the correct parameter
>Keep Unit Test Short, Sweet, and Visible

### Create Service
Create user service inside **src/user/**. see folder structure
```javascript
class UserService {
  constructor(props) {
    Object.assign(this, props);
  }

  async getById(id) {
    const params = {
      id,
    };

    return this.userRepository.get(params);
  }

  async filterAndSort(queryRequest) {
    return this.userRepository.filterAndSort(queryRequest);
  }

  create() {
    return {
      userName: 'bob',
      email: 'bob@sit.com',
    };
  }
}

module.exports = UserService;

```
### Run Unit Test ###
```
mocha test --recursive
```

[express]: <http://expressjs.com>
[node.js]: <http://nodejs.org>
[ES6]: <https://en.wikipedia.org/wiki/ECMAScript>
[Unit Testing]: <https://www.npmjs.com/package/sinon-chai>