Mocking functions and files while testing javascript app using Jest

This exactly is what mocking means

Mock in the English language means ‘make a replica or imitation of something’. So when instead of using the actual function, we use something that imitates like that function but isn’t exactly the same i.e. same number of arguments and similar return value, it’s referred to as mocking the actual function. Before going into HOW of it, let’s try and understand WHY to it.

Test Driven Development (TDD) is a software development process used in most of the projects these days. Every code snippet has corresponding tests for it so that if ever it fails or has unusual behaviour, one knows where to look for bugs and errors. We test each and every function individually, making debugging and understanding of the code simpler and easier.

Of the many functions we have, many of them involve calls to other functions, external API calls and use of node modules to perform certain tasks. The functions being executed or calls being made have already been tested separately, so if you are checking the result of the function as a whole, you are indirectly testing what’s already tested. Sounds silly, no.

The tests for the current function should just check whether the other functions and external calls are being made properly or not.

const add = (a, b) => (a + b);
const subtract = (a, b) => (a - b);
const multiply = (a, b) => (a * b);
const calculate = (num1, num2, operation){
switch(operation){
case 'add': result = add(num1, num2); break;
case 'sub': result = subtract(num1, num2); break;
case 'mul': result = multiply(num1, num2); break;
}
return result;
}

In the above example, given the functions add, subtract and multiply have already been tested independently. The test suites for the function calculate should just focus whether the correct function is being called based on the operation variable, that’s it. The calculate function tests shouldn’t actually call and execute the add, subtract or multiply function. Understand the importance of this by scaling it to a bigger problem. The functions are not as simple as add or subtract rather are very complex and have hundreds of lines of code and take considerably much more time to execute. Wouldn’t it make more sense to have a replica of the original function that isn’t as complex and tells us whether the function is called or not? In the current scenario, we can have a function that is similar to add function but not exactly the same.

const add = (a, b) => ('Add function is being called with values', a, 'and ', b);

Our new function appears like the original function or is a replica but skips all the complex part and tells us that the add function is being called with the given arguments. This is what mocking means. We can mock the actual function with our new function while testing and match the value returned by the new function and verify that the correct function is being called with correct values.


Having known the WHY of it, HOW to mock functions isn’t a very difficult job using Jest.

There are two ways to mock functions: Either by creating a mock function to use in test code or writing a manual mock to override a module dependency.

We will be mainly focusing on manual mocks in this post as our main aim is to learn how to override the actual implementation of a function, file or module. To mock any file first step is to tell Jest that you are planning to mock it.

jest.mock('abc.js'); // relative path of the file you plan to mock

After telling Jest that you will be mocking the particular file, you need to tell Jest what it should do, instead of executing the function. You can increase a counter or return a particular value to know that the function was called. You can define this object in the test file itself while telling Jest that you are mocking it.

jest.mock('abc.js', () => {
return {
function1: (args) => ('function1 is being called');
function2: (args) => ('function2 is being called');
function3: (args) => ('function3 is being called');
}
});

It basically does is that it overrides the exported object from the mocked file to return value of the callback. Hence in test file whenever you call function1 from abc.js it will return the value ‘function1 is being called’ instead of the actual value. So cool 😎

Say there is a function that does API call. While testing you don’t need to make that request. Instead, you can mock it to return a default data similar to what would actually come. In this approach, you’ll have to provide the same data in each and every file where you plan to mock the call.

Folder structure for default mock

In the given structure you plan to mock user.js, create a folder __mock__ inside src and then file user.js. In this file you can write all functions that are to be mocked and export them. So when you tell Jest you want to mock user.js, it will directly use this file for the mocked functions, instead of the original.

user.js file looks something like this

const add = (a, b) => (a + b);
const subtract = (a, b) => (a - b);
const multiply = (a, b) => (a * b);
module.exports = { add, subtract, multiply };

__mock__/user.js file :

const add = (a, b) => ('add two values');
const subtract = (a, b) => (Subtracts two values);
const multiply = (a, b) => ('Multiplies the two values');
module.exports = { add, subtract, multiply };
Follow the name convention as it is because it’s case sensitive

Now whenever we tell Jest to mock user.js, it will automatically take this definition. You don’t need to explicitly provide the callback which returns the new object.

jest.mock('path_to_user.js');//no callback required for mocked value

So now you can easily mock API calls or other functions, modules and files while following TDD and test your app nicely 💯.

You can view the Jest documentation for better understanding.