Jest Mocking For Beginners
By gobrain
Nov 28th, 2024
Jest is a powerful library for testing JavaScript applications. It offers many features that simplify unit testing. One of the features of Jest is mocking.
Jest mocking is a powerful feature that allows you to isolate the code you're testing by replacing its dependencies with controlled, fake implementations. This lets you write more focused and reliable tests.
Now, let's dive into Jest mocks and explore how they can be used effectively to test your JavaScript applications.
What is Mocking?
The term mocking is a testing technique that involves creating imitation versions, or mocks of objects, functions, or modules to isolate the code you’re testing. By using mocks, you can have control over how these elements behave without actually executing their real code.
Mocking lets you concentrate on testing a particular piece of code while pretending that the surrounding components are functioning as expected. This isolation helps uncover bugs and errors specific to the code under examination.
To list the benefits of mocking, they includes:
- Isolation for Precise Testing
- Controlled Behavior
- Handling Unavailable or Unstable Dependencies
- Reduced Costs
- Easy Simulations
When Should You Use Mocking?
Mocking is particularly helpful when dealing with external dependencies, such as APIs or databases. By creating mock versions of these dependencies, you can simulate their behavior and ensure your code interacts correctly with them, all without the complexities of real-world connections.
For example, imagine you have a function responsible for registering new users and sending them a welcome email. Instead of sending actual emails and relying on external email services, you can create a mock email service to simulate email sending behavior. This approach allows you to test different phases of the user registration process by isolating them from the external email module.
Mocking in Jest
Jest comes with a powerful mocking feature. The different types of mock in Jest include:
- Mock Functions
- Mock Modules
- Spies
Mock Functions
In Jest, function mocks allow you to define the behavior of functions without actually executing their code. Jest provides a simple way to create function mocks using the jest.fn()
method. This method creates a new mock function that you can customize according to your test requirements.
For example, you can define a mock function and set its return value using the mockReturnValue
method.
const myFunction = jest.fn();
myFunction.mockReturnValue(42);
// Test example
expect(myFunction()).toBe(42);
Alternatively, you can specify an entire custom implementation for the mock function using the mockImplementation
method instead of controlling a part of the original function.
const myFunction = jest.fn();
myFunction.mockImplementation((a, b) => a + b);
const result = myFunction(1,2)
// Test example
expect(result).toBe(3);
expect(myFunction).toHaveBeenCalledWith(1, 2);
Additionally, for asynchronous functions, you can also use methods like mockResolvedValue
, mockRejectedValue
, etc., to define their resolved or rejected values.
const myFunction = jest.fn();
myFunction.mockResolvedValue("Promise resolved successfully!");
// or
myFunction.mockRejectedValue(new Error("Error Message"));
expect(myFunction()).rejects.toThrow(new Error("Error Message"));
Mock Modules
In Jest, module mocks enable you to o simulate the behavior of external or internal modules. These modules can include databases, external services, APIs, or even other parts of the same application.
Suppose you have an internal math.js
module that performs math operations
// math.js
function add(a, b) {
return a + b;
}
function divide(a, b) {
return a / b;
}
module.exports = {
add,
divide
};
You can mock an entire module and and control the behavior of that module’s functions. For instance, consider the following example where we replace a function’s summation functionality with subtraction.
// math.test.js
const math = require("./math.js");
// Mocking the dependency
jest.mock("./math.js");
describe("add", () => {
it("should add two numbers", () => {
// Mock the add function to change behaviour of the function
// Now, the add fucntion will do subtraction
math.add.mockImplementation((a, b) => a - b);
// Call the function to be tested
const result = math.add(6, 4);
// Assert the result
expect(result).toBe(2);
});
// You can add more test cases for the add function here
});
You can also mock an external module. Let’s say you have a module named api.js
that makes HTTP requests with Axios, and you want to mock Axios behavior for testing purposes.
// api.js
const axios = require('axios');
async function fetchData() {
const response = await axios.get('https://api.example.com/data');
return response.data;
}
module.exports = { fetchData };
At this point, you can control Axios’s behavior by setting a new value for the response that the Axios get
method will resolve. This means that you isolate the code you’re testing from Axios, enabling you to test other processes, such as checking if the response displays correctly in the page or if the user sees an error when it occurs.
// api.test.js
const axios = require('axios');
const api = require('./api');
jest.mock('axios'); // This line mocks the axios module
test('fetchData should return mock data', async () => {
axios.get.mockResolvedValue({ data: 'mocked data' });
const result = await api.fetchData();
// This is for
expect(result).toBe('mocked data');
});
Spies
In Jest, Spies allow you watch over function calls as an additional feature. They captures information about their invocations. This makes it a dynamic tool for both monitoring and manipulating function behavior during testing.
Jest provides a built-in spying mechanism through the jest.spyOn
function. It allows you to create a spy for a specific function. Consider the following example where jest.spyOn
is used to create a spy for the add
function in the mathUtils
module. Then, various assertions are made using the spy, such as checking if the function was called with specific arguments and how many times it was called.
// Example module
const mathUtils = {
add: (a, b) => a + b,
subtract: (a, b) => a - b,
};
// Test case
test('Testing the add function', () => {
// Create a spy on the 'add' function
const addSpy = jest.spyOn(mathUtils, 'add');
addSpy.mockImplementation((a,b) => a * b);
// Call the function
const result = mathUtils.add(2, 3);
// Assertions
expect(result).toBe(6); // Check the result
expect(addSpy).toHaveBeenCalledTimes(1); // Check if the spy was called once
expect(addSpy).toHaveBeenCalledWith(2, 3); // Check if the spy was called with specific arguments
// Restore the original function (optional)
addSpy.mockRestore();
});
Actually, as you may realize jest.spyOn
and jest.fn
are so similar, but they serve slightly different purposes. jest.spyOn
is used to create a spy on existing functions or methods, especially when you want to temporarily mock or change their behavior during testing. On the other hand, jest.fn
is used to create standalone mock functions that you can use to define custom behavior or replace functions entirely during testing.
Conclusion
In summary, using mocks in testing allows you to isolate the code you are testing from certain dependencies, functions, or modules. They help you create a controlled environment, catch bugs early, and ensure that your code interacts seamlessly with its dependencies, all while reducing costs and improving overall efficiency.
Remember that, using mocks does not mean that you should avoid testing external modules. They allow you to test other processes except for those modules.
In this article we have discussed the different types of mocking in Jest along with examples.
Thank you for reading.