如何模拟用 jest.mock 模拟的 class 的实例方法?
How to mock instance methods of a class mocked with jest.mock?
如何为使用 jest.mock
模拟的 class 模拟实例方法?
比如一个classLogger
被mock了:
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();
});
});
自动模拟
除非使用 __mocks__
目录指定手动模拟,否则调用 jest.mock
会自动模拟被模拟模块的所有导出。
因此,这一行 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 的自动模拟功能。有关更多信息,请参阅 docs。
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()
调用被提升,所以你不能先定义一个变量,然后在工厂函数中使用它,除非变量以[=22为前缀=].因此我们可以访问工厂内部的 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();
});
});
如何为使用 jest.mock
模拟的 class 模拟实例方法?
比如一个classLogger
被mock了:
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();
});
});
自动模拟
除非使用 __mocks__
目录指定手动模拟,否则调用 jest.mock
会自动模拟被模拟模块的所有导出。
因此,这一行 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 的自动模拟功能。有关更多信息,请参阅 docs。
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()
调用被提升,所以你不能先定义一个变量,然后在工厂函数中使用它,除非变量以[=22为前缀=].因此我们可以访问工厂内部的 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();
});
});