Jest - Mocking



In this chapter, we'll learn about mocking in Jest. Mocking lets you replace real functions, modules, or API calls with mock versions so you can test parts of your code independently.

Using mock makes your tests faster, more reliable, and lets you focus on the core logic while controlling external dependencies. Let's get started.

What is Mocking in Jest?

Mocking in Jest means replacing real functions, modules, or components with mock versions (fake versions that act like the real ones) to test how your code interacts with them. This helps you focus on testing specific parts of your code while avoiding the need to rely on external systems, making your tests faster and more reliable.

Mocking is especially helpful when:

  • External services(like APIs or databases) are slow, unavailable, or not needed for the test.
  • You want to focus on testing a specific part of your code without interference from other parts.
  • You need to simulate errors or unusual situations(edge cases) that might be hard to reproduce with real data.

Why Mocking is Important in Jest?

Mocking is important because it:

  • Isolates code: You can test specific parts of your code independently by replacing real dependencies with mock.
  • Improves test: Mocking avoids calling actual functions or external systems, making tests run faster.
  • Provides control: Mocking allows you to define how dependencies behave, such as returning specific values or causing errors.
  • Simplifies testing edge cases: Mocking makes it easier to test rare situations, like errors or unexpected data from external services.

Types of Mocking in Jest

In Jest, there are different types of mocking you can use depending on what you need to test. Here are the main types of mocking available:

Jest - Function Mocking

Function mocking in Jest means creating fake versions of functions to use in tests. These mocks behave like real ones but allow you to control their actions, track calls, decide what they return, and test different situations without running the actual code.

Creating a Mock Function

You can create a mock function using jest.fn(). It behaves like the real function but lets you control its behavior, such as the return value.

// Mock returns 6
const mockFunction = jest.fn().mockReturnValue(6); 

Tracking Calls

You can track how many times a mock function was called and what arguments it received.

const mockFunction = jest.fn();
mockFunction(1, 2);

// Verifies mock was called with 1 and 2
expect(mockFunction).toHaveBeenCalledWith(1, 2); 

Simulating Multiple Return Values

You can make a mock function return different values for different calls using mockReturnValueOnce().

const mockFunction = jest.fn()

// First call returns 1
.mockReturnValueOnce(1)  

// Second call returns 2
.mockReturnValueOnce(2); 

Custom Implementation

You can define custom behavior for your mock function using mockImplementation().

// Adds two numbers
const mockFunction = jest.fn().mockImplementation((a, b) => a + b); 

Resetting Mocks

After each test, you can reset the mock's state using mockReset(). This ensures that one test doesn't affect the next.

const mockFunction = jest.fn();

// Resets the mock's state
mockFunction.mockReset(); 

Jest - Module Mocking

Sometimes, you may want to mock an entire module instead of just a function. This is useful when you want to test specific parts of your code without relying on the actual module implementation (e.g., an API or database).

How to Mock a Module?

To mock a module, you can use jest.mock(). This replaces the real module implementation with a mock version.

Example

// Assume we have a math.js module that contains an add function
jest.mock('./math');  // Mock the math module
import * as math from './math';

test('mock module example', () => {

    // Mock the add function to return 10
    math.add.mockReturnValue(10); 
    
    // The mock returns 10, not the real implementation
    expect(math.add(2, 3)).toBe(10);  
});

Jest - Manual Mocks

Manual mocks give you more control over Jest's mocking. You can create your own mock for a module, put it in a __mocks__ directory, and Jest will use your mock instead of the real module during tests.

How to Create Manual Mocks?

In Jest, you can create manual mocks by following these simple steps:

  • Create a __mocks__ folder: Place it next to the module you want to mock.
  • Define the mock behavior inside the __mocks__ folder.

Example

  • Original module (math.js): This is the real implementation you want to mock.
// math.js
export const add = (a, b) => a + b;
  • Manual mock in __mocks__/math.js: Create the mock version of the module with custom behavior.
  • // __mocks__/math.js
    export const add = jest.fn(() => 42);  // Always returns 42
    
  • Use the mock in your test: Jest automatically uses the mock whenever the module is imported in your test.
  • jest.mock('./math');  // Mock the module
    expect(add()).toBe(42);  // Test mock behavior
    

    Jest Mocking Timers

    Timer mocking in Jest allows you to control functions like setTimeout, setInterval, and clearTimeout during your tests. This is helpful when you want to test time-related behaviors without waiting for actual time delays.

    How to Mock Timers?

    To mock timers, use jest.useFakeTimers() to replace the real timers with fake ones, and control the passage of time with methods like jest.runAllTimers().

    Example

    test('mocking setTimeout with fake timers', () => {
        // Enable fake timers
        jest.useFakeTimers();  
        const mockCallback = jest.fn();  
        
        // Set a timeout with the mock callback
        setTimeout(mockCallback, 1000);  
        
        // Move time forward and trigger all timers
        jest.runAllTimers();  
        
        // Verify that the mock callback was called
        expect(mockCallback).toHaveBeenCalled();  
    });
    

    Jest - Mocking Classes

    In Jest, you can mock class methods or entire classes, which is helpful when testing code that depends on classes. Mocking lets you replicate class behavior without running the actual code or causing any side effects.

    How to Mock a Class?

    To mock a class, you can use jest.fn() for individual methods or mock the entire class.

    Example

    // Define the Car class
    class Car {
        start() {
            return 'Car started';
        }
    }
    
    // Mock the start method of the Car class
    test('mocking class methods', () => {
        // Mocking start method
        const mockStart = jest.fn().mockReturnValue('Mocked start');
    
        const car = new Car();
        // Replace the start method with the mock
        car.start = mockStart;
    
        // Verify the mock behavior
        expect(car.start()).toBe('Mocked start');
    });
    

    Jest - Mocking API Calls

    Mocking API calls in Jest means creating fake responses for API requests instead of actually connecting to a real API. This helps make your tests faster and more reliable because you don't need to depend on real external services or the internet to run them.

    How to Mock API Calls?

    You can mock libraries like axios or fetch to pretend as if the server is responding, without actually making a request to a real server.

    Example

    // This mocks the axios library to prevent actual API calls
    jest.mock('axios');
    import axios from 'axios';
    
    test('mocking API call', async () => {
        // Mock the response of axios.get()
        axios.get.mockResolvedValue({ data: { user: 'John' } });
    
        // Call the API function (same as real code)
        const response = await axios.get('/user');
    
        // Check if the mock response is returned
        expect(response.data.user).toBe('John');
    });
    

    Jest - Spy Mocks

    Spy mocks track how existing functions or methods are called without changing their behavior. You can use jest.spyOn() to watch a method on an object and then check how it was used in your tests.

    How to Use Spy Mocks?

    You can use jest.spyOn() to observe how a function or method was called.

    Example

    // Creating a car object with a startEngine method
    const car = {
        startEngine: () => {
            return 'Engine started';
        },
      };
      
    test('spying on startEngine method', () => {
        // Spy on the startEngine method
        const spy = jest.spyOn(car, 'startEngine');  
    
        car.startEngine();  // Call the method
    
        // Check if startEngine was called
        expect(spy).toHaveBeenCalled();
    
        spy.mockRestore();  // Restore the original method
    });
    
    Advertisements