DEV Community

Cover image for Helper Functions for Assertions (Jest & Node.js)
Malcolm R. Kente
Malcolm R. Kente

Posted on

Helper Functions for Assertions (Jest & Node.js)

Whether you are new to software development or have been at it for a while, software testing is something you are likely to encounter. It is an integral part of any development process.

Unit Tests πŸ§ͺ

There is an expectancy for developers to write unit tests for their application's code. Unit tests are the right way of testing the smallest unit of code within a system. Ideally, these are isolated pieces of code that exist in separate files on an application.

Unit tests consist of testing individual methods and functions of your software's classes, components, or modules. Unit tests are, in general, relatively cheap to automate and can be run very quickly by a continuous integration server.

The backstory πŸ”™

So recently, I've been improving some of the projects on my GitHub. One of the main points has been to increase the code coverage by writing unit tests for my projects.

I've become quite accustomed to using the Jest testing framework. Not a knock to any other testing frameworks, but Jest has become a recent favorite go-to of sorts. Thus I decided to implement testing using Jest on a Node.js project of mine.

Disclaimer ‼️ Mocha/Chai could've also been a viable option, but I wanted to play around the backend with Jest this time around. πŸ™ˆ

My Problem πŸ€”

Something that kept repeatedly happening is similar assertions that came up for multiple modules.

Module 1️⃣

isNotNumber.helper.js

module.exports = (incomingId) => isNaN(incomingId);
Enter fullscreen mode Exit fullscreen mode

isNotNumber.helper.test.js

const isNotNumber = require("../isNotNumber.helper");

describe("isNotNumber helper function unit tests", () => {
  it("should validate incoming module truthiness", () => {
    expect(isNotNumber).not.toBeNull();
    expect(isNotNumber).toBeTruthy();
  });

  it("should validate string type as true", () => {
    const results = isNotNumber("dummy")

    expect(results).not.toBe(false);
    expect(results).toBe(true);
  });

  it("should validate number type as false", () => {
    const results = isNotNumber(1)

    expect(results).not.toBe(true);
    expect(results).toBe(false);
  });
});
Enter fullscreen mode Exit fullscreen mode

Module 2️⃣

isObjectPropertyEmpty.helper.js

module.exports = (incomingObject) =>
  Object.values(incomingObject).some((key) => key === null || key === "");
Enter fullscreen mode Exit fullscreen mode

isObjectPropertyEmpty.helper.test.js

const isObjectPropertyEmpty = require("../isObjectPropertyEmpty.helper");

describe("isObjectPropertyEmpty helper function unit tests", () => {
  it("should validate incoming module truthiness", () => {
    expect(isObjectPropertyEmpty).not.toBeNull();
    expect(isObjectPropertyEmpty).toBeTruthy();
  });

  it("should validate object with empty field as true", () => {
    const results = isObjectPropertyEmpty({ id: "" })

    expect(results).not.toBe(false);
    expect(results).toBe(true);
  });

  it("should validate object with non-empty field as false", () => {
    const results = isObjectPropertyEmpty({ id: 1 }

    expect(results).not.toBe(true);
    expect(results).toBe(false);
  });
});
Enter fullscreen mode Exit fullscreen mode

I realized quickly that this could be an issue that may repeat over time with many of the other modules. It probably is acceptable to re-write the same assertions in multiple tests, but it felt very impractical and not-very D.R.Y.

The Solution πŸ’‘

The thing that ended up being helpful was refactoring and creating "Helper Functions" that took care of covering the repeating assertions.

The process was as simple as:

  1. Create a function(s) with the assertion logic in a separate file (use logical naming constructs). βœ…
  2. Call on the required helper when writing unit tests. βœ…

Helper functions with assertion logic
validators.js

module.exports = {
  validateTruthiness: (received) => {
    expect(received).not.toBeNull();
    expect(received).toBeTruthy();
  },
  validateBooleanValues: (received, boolean) => {
    expect(received).not.toBe(!boolean);
    expect(received).toBe(boolean);
  },
  ....
}
Enter fullscreen mode Exit fullscreen mode

Using helpers in the unit tests
isNotNumber.helper.test.js

const isNotNumber = require("../isNotNumber.helper");

const {
  validateTruthiness,
  validateBooleanValues,
} = require("../../../utils/validators");

describe("isNotNumber helper function unit tests", () => {
  it("should validate incoming module truthiness", () => {
    validateTruthiness(isNotNumber);
  });
  it("should validate string type as true", () => {
    validateBooleanValues(isNotNumber("dummy"), true);
  });

  it("should validate number type as false", () => {
    validateBooleanValues(isNotNumber(1), false);
  });
});
Enter fullscreen mode Exit fullscreen mode

isObjectPropertyEmpty.helper.test.js

const isObjectPropertyEmpty = require("../isObjectPropertyEmpty.helper");

const {
  validateTruthiness,
  validateBooleanValues,
} = require("../../../utils/validators");

describe("isObjectPropertyEmpty helper function unit tests", () => {
  it("should validate incoming module truthiness", () => {
    validateTruthiness(isObjectPropertyEmpty);
  });

  it("should validate object with empty field as true", () => {
    validateBooleanValues(isObjectPropertyEmpty({ id: "" }), true);
  });

  it("should validate object with non-empty field as false", () => {
    validateBooleanValues(isObjectPropertyEmpty({ id: 1 }), false);
  });
});
Enter fullscreen mode Exit fullscreen mode

Conclusion 🏁

That's pretty much it! Refactoring and introducing helper functions that took care of the assertion logic took away the need to repeat code.

As I soon found out, more tests also had identical assertions, so the need to have a test validation file became warranted. In the end, a single file housed all the validators used throughout the project.

I'm pretty sure other approaches to this situation I found myself in.

Let me know what you think about this?
And feel free to share any improvement tips for this. ✌️


Find the above code snippets πŸ‘‰ here πŸ‘ˆ
Full repo πŸ‘‰ here πŸ‘ˆ

Top comments (0)