Sling Academy
Home/Node.js/Writing Unit Tests in ExpressJS: A Developers’ Guide

Writing Unit Tests in ExpressJS: A Developers’ Guide

Last updated: January 18, 2024

Introduction

Unit testing is an essential aspect of modern web development. It enables developers to verify the functionality of individual parts of their application independently from each other, improving code reliability and facilitating smoother integration. When building web applications with Node.js, using a framework like ExpressJS, unit testing becomes especially vital due to the asynchronous nature of Node’s execution model.

Understanding Unit Testing in ExpressJS

In the context of an ExpressJS application, unit tests focus on the smallest parts of the application: the functions and methods. These include middleware, request handlers, and utility functions. The goal is to test these components in isolation to ensure they behave as expected. A robust testing framework and a well-thought-out test strategy are key to effective testing.

Choosing a Testing Framework

Several testing frameworks are suitable for Node.js applications, but for ExpressJS, popular choices include Mocha, Jest, and Jasmine. Mocha, paired with an assertion library like Chai, offers a flexible and well-documented foundation for writing tests. Jest, meanwhile, comes with everything you need bundled in, making setup simpler. This guide will focus on Mocha and Chai.

Setting Up the Environment

First, you’ll need to set up Mocha and Chai in your ExpressJS project:

  1. Install Mocha and Chai with npm: npm install mocha chai --save-dev
  2. Add a test script in your package.json file:
    {
      "scripts": {
        "test": "mocha"
      }
    }

Writing Your First Unit Test

Assuming you have a route that adds two numbers and returns the sum, let’s test it with the following code:

const expect = require('chai').expect;
const request = require('supertest');
const app = require('../app');

describe('GET /add', function() {
  it('should return the sum of two numbers', function(done) {
    request(app)
      .get('/add?num1=5&num2=10')
      .end(function(err, res) {
        expect(res.statusCode).to.equal(200);
        expect(res.body.result).to.equal(15);
        done();
      });
  });
});

Here we’re using the supertest library to simulate HTTP requests.

Testing Middleware

Middleware in ExpressJS are functions that have access to the req, res, and next objects. Writing unit tests for middleware follows similar principles as testing routes:

const expect = require('chai').expect;
const httpMocks = require('node-mocks-http');
const myMiddleware = require('../middleware/myMiddleware');

describe('MyMiddleware Function', function() {
  it('should do something', function() {
    const request  = httpMocks.createRequest();
    const response = httpMocks.createResponse();
    const next = sinon.spy();

    myMiddleware(request, response, next);
    expect(next.calledOnce).to.be.true;
  });
});

Mocking External Services

When your unit tests involve external services or databases, it is best practice to mock them:

const sinon = require('sinon');
const myDatabase = require('../database/myDatabase');

describe('Database Function', function() {
  before(function() {
    sinon.stub(myDatabase, 'getUser').resolves({ id: 1, name: 'John Doe' });
  });

  after(function() {
    myDatabase.getUser.restore();
  });

  it('should get a user by id', async function() {
    const user = await myDatabase.getUser(1);
    expect(user.name).to.equal('John Doe');
  });
});

Continuous Testing

To run tests continuously during development, consider using a tool like Nodemon to restart the Mocha test suite when changes in your codebase are detected:

  1. Install Nodemon: npm install nodemon --save-dev
  2. Change the test script in package.json to:
    {   "scripts": {     "test": "nodemon --exec mocha"   } }

Conclusion

Unit testing in ExpressJS may seem daunting at first, but with the right framework and by breaking down the process into manageable pieces, it becomes a powerful way to ensure that your application is well-built and resilient to change. Test early and often to make your development smoother and your deployments safer.

Next Article: Express + Handlebars: How to Render JSON Data

Previous Article: Express + Handlebars + TypeScript: Tutorial & Examples

Series: Node.js & Express Tutorials

Node.js

You May Also Like

  • NestJS: How to create cursor-based pagination (2 examples)
  • Cursor-Based Pagination in SequelizeJS: Practical Examples
  • MongooseJS: Cursor-Based Pagination Examples
  • Node.js: How to get location from IP address (3 approaches)
  • SequelizeJS: How to reset auto-increment ID after deleting records
  • SequelizeJS: Grouping Results by Multiple Columns
  • NestJS: Using Faker.js to populate database (for testing)
  • NodeJS: Search and download images by keyword from Unsplash API
  • NestJS: Generate N random users using Faker.js
  • Sequelize Upsert: How to insert or update a record in one query
  • NodeJS: Declaring types when using dotenv with TypeScript
  • Using ExpressJS and Multer with TypeScript
  • NodeJS: Link to static assets (JS, CSS) in Pug templates
  • NodeJS: How to use mixins in Pug templates
  • NodeJS: Displaying images and links in Pug templates
  • ExpressJS + Pug: How to use loops to render array data
  • ExpressJS: Using MORGAN to Log HTTP Requests
  • NodeJS: Using express-fileupload to simply upload files
  • ExpressJS: How to render JSON in Pug templates