如何用jest.mock模拟类的实例方法?



如何为正在被jest.mock模拟的类模拟实例方法?

例如,模拟一个类Logger:

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();
});
});

自动模拟

调用jest.mock将自动模拟正在模拟的模块中的所有导出,除非使用__mocks__目录指定了手动模拟。

所以,jest.mock("./Logger")这行已经自动用模拟函数替换了Logger构造函数和它的所有方法,允许我们测试这些函数的行为。

Logger创建的实例相关的信息保存在Logger.mock.instances中,因此我们可以使用它来测试方法是否被正确调用。

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();
});
});

使用模块工厂参数

您还可以通过将工厂函数作为第二个参数传递给jest.mock来显式地提供模块工厂。因此,现在将使用提供的模块工厂而不是Jest的自动锁定特性。参考文档获取更多信息。

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();
});
});

注意:jest.mock()调用是提升的,因此您不能首先定义一个变量,然后在工厂函数中使用它,除非该变量以mock为前缀。因此,我们可以在工厂内部访问mockMethod1

手动模拟

您可以通过创建位于__mocks__/Logger.js的手动模拟来实现与模块工厂函数类似的行为。现在,只需调用jest.mock,就可以跨测试文件使用这个模拟实现。

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

用法类似于模块工厂函数,但现在您还必须在测试中导入模拟方法。

注意:你仍然需要使用原来的模块路径,不包括__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();
});
});

最新更新