Jest Mocking for Unit Testing

CodeStax.Ai
5 min readApr 15, 2024

Mocking is a technique used in software development to separate the unit under test from its dependencies, especially when doing unit tests. It’s crucial to test a unit of code’s specific functionality independently, as opposed to how it interacts with other components or systems, while designing unit tests. Developers can use “Mocks,” which are simulated copies of actual software components. Although they mimic the original versions behaviour, these fake versions don’t really run the original code. Rather than utilizing the actual external dependencies, they imitate the behaviour, enabling developers to test their code.

For example, consider a scenario of testing a function to add a record to the database, before adding the record it needs to pass the authentication. Authentication function returns true for authenticated user and false for unauthenticated user. You can use a mocked function for the authentication module that always returns a successful authentication response. This ensures that the focus of the test remains on the functionality of the database without being affected by the complexity of the authentication process.

Mocking of Modules and functions:

jest.mock() => Mock the entire Module.

jest.fn() => Mock the functions without mocking the entire module.

jest.spyOn() => Spy the function.

Before delving into each function, we need to understand the built-in function provided by Jest for mocking.

mockResolvedValueOnce — is used to simulate asynchronous functions that give back a Promise. To be more precise, it sets the resolved value of the Promise it returns and mocks a single function call. When testing asynchronous functions, this is helpful since it allows you to manage the resolved value of the Promise that the function returns for particular test cases.

mockRejectedValueOnce — is used to simulate asynchronous functions that return a Promise but ought to be refused. It sets the rejected value of the Promise it returns and mocks a single function call. This comes in handy for situations where you need to evaluate an asynchronous function’s ability to handle rejected Promises correctly.

mockReturnValueOnce — is used to simulate synchronous operations. It sets the return value and mocks a single call to the function or method. This is helpful in test scenarios where you need to manage a function or method’s return value for particular test cases.

Let us see each method of mocking one by one

Mocking using jest.mock():

In the below calculator.js there are three functions namely addition, subtraction, multiplication. Let us see how to mock it in the calculator.test.js file.

Here we mock the calculator module entirely.

// Calculator.js

async function addition (a,b) {
return a+b;
}
async function subtraction (a,b) {
return a-b;
}
async function multiplication (a,b) {
return a*b;
}

exports.addition = addition;
exports.subtraction = subtraction;
exports.multiplication = multiplication;
//Calculator.test.js
//Import the module

const calculator = require('./calculator');

//Mock the imported module
jest.mock('./calculator'); // Here mention the path to the file

// While mocking it is not required to give exact value
test('Mocking of addition function', async () => {
calculator.addition.mockReturnValueOnce(5);
let res = calculator.addition(2,10);
expect(res).toBe(5);
});

test('Mocking of subtraction function', async () => {
calculator.subtraction.mockReturnValueOnce(5);
let res = calculator.subtraction(2,10);
expect(res).toBe(5);
});

test('Mocking of multiplication function', async () => {
calculator.multiplication.mockReturnValueOnce(5);
let res = calculator.multiplication(2,10);
expect(res).toBe(5);
});

Mocking Using jest.fn():

Here we mock only two functions (addition and subtraction) present in the module.

Let us consider the same example (calculator.js) for understanding.

//Calculator.test.js
//Import the module

const calculator = require('./calculator');

//Mock the funtion the we want to use.
calculator.addition = jest.fn(); // Mocking of addition function
calculator.subtraction = jest.fn(); // Mocking of subtraction function.

test('Mocking of addition function', async () => {
calculator.addition.mockReturnValueOnce(5);
let res = calculator.addition(2,10);
expect(res).toBe(5);
});

test('Mocking of subtraction function', async () => {
calculator.subtraction.mockReturnValueOnce(5);
let res = calculator.subtraction(2,10);
expect(res).toBe(5);
});

Mocking using jest.spyOn():

It is used to mock the function, in addition to that we can able to track our method being called without changing the implementation.

Let us consider the same example (calculator.js) for understanding.

//Calculator.test.js
//Import the module

const calculator = require('./calculator');

//Mock the funciton that we want.
const addSpy = jest.spyOn(calculator, 'addition'); // Mocking of addition function
const subSpy = jest.spyOn(calculator, 'subtraction'); // Mocking of subtraction function

test('Mocking of addition function', async () => {
addSpy.mockReturnValueOnce(12);
let res = calculator.addition(2,10);
expect(res).toBe(12);
});

test('Mocking of subtraction function', async () => {
subSpy.mockReturnValueOnce(8);
let res = calculator.subtraction(2,10);
expect(res).toBe(8);
});

Now we will see how to mock the function present in the different modules.

For example, consider the scenario of adding a record to the database. In actual flow first it will go to authentication (code for authentication is present in the another module) and after that it will go add a record. While testing the code for adding the record to the database there is no need to test the code for authentication. So that we can mock the authentication to return the success response and then we can test the code for our adding the record to database.

Consider the file Authentication.js, it has the function named verifyUser which is responsible for verifying the user who is authorised user. It returns a Boolean value true and false.

Consider the file addRecord which is responsible for adding the record.

// Authentication.js
function verifyUser (userId) {

// it returns true for authorized user and false for unauthorized
// consider userId is present in the params
// logic to verify user

}
exports.verifyUser = verifyUser;

// AddRecord.js

const Authentication= require("./Authentication.js");

function addRecord (params) {
try {
if(Authentication.verifyUser(userId)) {

//logic to add record
return true;
}
else {
return false
}
}
catch (error) {
return "Error Occurred"
}
}
exports.addRecord = addRecord;

Let us write mock test case for it:

// AddRecordtest.test.js
const AddRecord = require('./AddRecord');
const Authentication = require('./Authentication');
jest.mock('./Authentication');

// consider variable params has declared and has the data to be added.

test('Authentication should return true ', async () => {

// Set up mocks
// filename.methodtomock.mockResolvedValueOnce(value/Message) -> The function call completed without errors.
// filename.methodtomock.mockRejectedValueOnce(error) -> Fail/Reject the function call.
// no need to give exact value or number of arguments.

Authentication.verifyUser.mockResolvedValueOnce(true);

//Perform the function calls
let result = AddRecord.addRecord(params); //Params that need to add

// Verify mocks were called
expect(result).toBe(true);
});

test('Authentication should return false', () => {

// Set up mocks
// filename.methodtomock.mockResolvedValueOnce(value/Message) -> The function call completed without errors.
// filename.methodtomock.mockRejectedValueOnce(error) -> Fail/Reject the function call.
// no need to give exact value or number of arguments.
Authentication.verifyUser.mockResolvedValueOnce(false);

//Perform the function call
let result = AddRecord.addRecord(params);

// Verify mocks were called
expect(result).toBe(false);
});

test('Authentication should throw error ', async () => {

// Set up mocks
// filename.methodtomock.mockResolvedValueOnce(value/Message) -> The function call completed without errors.
// filename.methodtomock.mockRejectedValueOnce(error) -> Fail/Reject the function call.
// no need to give exact value or number of arguments as well as the message.

Authentication.verifyUser.mockRejectedValueOnce("Error in authentication");

//Perform the function call
let result = AddRecord.addRecord(params);

// Verify mocks were called
expect(result).toBe("Error Occurred");
});

About the Author:

Chandruvasan S is a Software Developement Engineer — Intern at CodeStax.Ai, where he contributes to various projects and learns about the intricacies of web development. With a keen interest in both front-end and back-end technologies, Chandruvasan enjoys tackling challenges and exploring new concepts in the field.

About CodeStax.Ai

At CodeStax.Ai, we stand at the nexus of innovation and enterprise solutions, offering technology partnerships that empower businesses to drive efficiency, innovation, and growth, harnessing the transformative power of no-code platforms and advanced AI integrations.

--

--

CodeStax.Ai

Tech tales from our powerhouse Software Engineering team!