Blog

How to properly mock in Jest

October 31, 2023
5
min read
IconIconIconIcon
We'll teach you what a mock is and how to do it right

How to Mock a Service in a Class Using JestJS

In a real-world codebase, classes often depend on services that perform tasks such as database access or API calls. These dependencies can make unit testing difficult, as you need to isolate the class you're testing. JestJS provides several ways to mock these services, allowing you to control their behavior and test your class in isolation.

Let's consider a simple class UserService that depends on a DatabaseService:

class DatabaseService {
  saveUser(user) {
    // Code to save user to the database 
  }
}
class UserService {
  constructor(databaseService) {
    this.databaseService = databaseService;
  } 
  
  createUser(user) {
    this.databaseService.saveUser(user);
  }
}

class DatabaseService {
saveUser(user) {
  // Code to save user to the database
}
}

class UserService {
constructor(databaseService) {
  this.databaseService = databaseService;
}

createUser(user) {
  // Some logic to create a user
  this.databaseService.saveUser(user);
}
}

Mocking a Service with jest.fn()

You can use jest.fn() to create a mock function that replaces the saveUser method of DatabaseService. This allows you to control the behavior of DatabaseService and test UserService in isolation [7].

const mockSaveUser = jest.fn();
const databaseService = { saveUser: mockSaveUser };
const userService = new UserService(databaseService);

userService.createUser({ name: 'John Doe' });

expect(mockSaveUser).toHaveBeenCalledWith({ name: 'John Doe' });

Mocking a Service with jest.spyOn()

Another way to mock a service is to use jest.spyOn(). This function creates a mock function similar to jest.fn(), but it also keeps track of the original function. This allows you to call the original function while still being able to make assertions about how it was called [7].

const databaseService = new DatabaseService();
const userService = new UserService(databaseService);

jest.spyOn(databaseService, 'saveUser').mockImplementation(() => {});

userService.createUser({ name: 'John Doe' });

expect(databaseService.saveUser).toHaveBeenCalledWith({ name: 'John Doe' });

Mocking a Service with jest.mock()

In more complex scenarios, you might want to use jest.mock() to automatically mock an entire module. This is particularly useful when the service you're mocking is imported from another module [2].

jest.mock('./DatabaseService');

const databaseService = require('./DatabaseService');
const userService = new UserService(databaseService);

userService.createUser({ name: 'John Doe' });

expect(databaseService.saveUser).toHaveBeenCalledWith({ name: 'John Doe' });

In this example, calling jest.mock('./DatabaseService') replaces DatabaseService with a mock constructor. You can then use this mock constructor to create a databaseService instance and pass it to UserService.

Share this post
IconIconIconIcon

Checkout our latest post

Some stuff we want to share with you

No items found.

Never write a unit test again

npm i -D deepunit
yarn add -D deepunit