admin管理员组

文章数量:1303404

How can the instance methods be mocked for a class that is being mocked with jest.mock?

For example, a class Logger is mocked:

import Person from "./Person";
import Logger from "./Logger";

jest.mock("./Logger");

describe("Person", () => {
  it("calls Logger.method1() on instantiation", () => {
    Logger.method1.mockImplementation(() => {}) // This fails as `method1` is an instance method but how can the instance method be mocked here?
    new Person();
    
    expect(Logger.method1).toHaveBeenCalled();
  });
});

How can the instance methods be mocked for a class that is being mocked with jest.mock?

For example, a class Logger is mocked:

import Person from "./Person";
import Logger from "./Logger";

jest.mock("./Logger");

describe("Person", () => {
  it("calls Logger.method1() on instantiation", () => {
    Logger.method1.mockImplementation(() => {}) // This fails as `method1` is an instance method but how can the instance method be mocked here?
    new Person();
    
    expect(Logger.method1).toHaveBeenCalled();
  });
});
Share edited May 17, 2022 at 19:44 Som Shekhar Mukherjee 8,1682 gold badges15 silver badges32 bronze badges asked May 17, 2022 at 19:05 surajs02surajs02 4712 gold badges8 silver badges20 bronze badges 4
  • have yout tried import Logger from jest.mock("./Logger")? – Some random IT boy Commented May 17, 2022 at 19:15
  • that gives the error String literal expected – surajs02 Commented May 17, 2022 at 19:16
  • Sorry, I meant const Logger = jest.mock("./Logger") – Some random IT boy Commented May 17, 2022 at 19:21
  • That makes sense but Logger.method1 gives error Property 'method' does not exist on type '"./Logger"' – surajs02 Commented May 17, 2022 at 19:23
Add a ment  | 

1 Answer 1

Reset to default 5

Automatic Mocking

Calling jest.mock automatically mocks all the exports from the module being mocked unless a manual mock is specified using the __mocks__ directory.

So, this line jest.mock("./Logger") has automatically replaced the Logger constructor and all of it's methods with mock functions allowing us to test how these functions behave.

And the information related to the instances created by Logger is saved in Logger.mock.instances, so we can use this to test if the methods are being called properly.

import Person from "./Person";
import Logger from "./Logger";

jest.mock("./Logger");

describe("Person", () => {
  it("calls method1 on instantiation", () => {
    const p = new Person();
    // Logger constructor should have been called
    expect(Logger).toHaveBeenCalled();
    
    const mockLoggerInstance = Logger.mock.instances[0];
    const mockMethod1 = mockLoggerInstance.method1;
    // method1 should have also been called
    expect(mockMethod1).toHaveBeenCalled();
  });
});

Using Module Factory Parameter

You can also explicitly provide a module factory by passing in a factory function as the second argument to jest.mock. So, now the provided module factory would be used instead of Jest's automocking feature. Refer the docs for more information.

import Person from "./Person";
import Logger from "./Logger";

const mockMethod1 = jest.fn();
jest.mock("./Logger", () =>
  jest.fn().mockImplementation(() => ({
    method1: mockMethod1,
  }))
);

describe("Person", () => {
  it("calls method1 on instantiation", () => {
    const p = new Person();
    // Logger constructor should have been called
    expect(Logger).toHaveBeenCalled();
    // method1 should have also been called
    expect(mockMethod1).toHaveBeenCalled();
  });
});

Note: jest.mock() calls are hoisted, so you cannot first define a variable and then use it inside a factory function unless the variable is prefixed with mock. And because of this we can access mockMethod1 inside the factory.

Manual Mock

You can achieve a similar behavior to module factory function by creating a manual mock located at __mocks__/Logger.js. And now this mock implementation can be used across test files by simply calling jest.mock.

// __mocks__/Logger.js
const mockMethod1 = jest.fn();
const mockLogger = jest.fn(() => ({
  method1: mockMethod1,
}));

Usage is similar to the module factory function but you now also have to import the mocked method in your test.

Note: You still need to use the original module path, don't include __mocks__.

import Person from "./Person";
import Logger, { mockMethod1 } from "./Logger";

jest.mock("./Logger");

describe("Person", () => {
  it("calls method1 on instantiation", () => {
    const p = new Person();
    // Logger constructor should have been called
    expect(Logger).toHaveBeenCalled();
    // method1 should have also been called
    expect(mockMethod1).toHaveBeenCalled();
  });
});

本文标签: javascriptHow to mock instance methods of a class mocked with jestmockStack Overflow