如何使用玩笑模拟构造函数实例化 class 实例?
How to mock a constructor instantiated class instance using jest?
给定实例化并使用另一个 class Logger
的 class Person
,如何验证 Logger
的方法何时被调用Person
在下面的例子中被实例化了?
// Logger.ts
export default class Logger {
constructor() {}
log(m: String) {
console.log(m);
// Other operations that are outside testing (e.g., file write).
throw Error('error');
}
}
// Person.ts
import Logger from "./Logger";
export default class Person {
constructor() {
const logger = new Logger();
logger.log('created');
}
// ...
}
// Person.test.ts
import Person from "./Person";
import Logger from "./Logger";
describe('Person', () => {
it('calls Logger.log() on instantiation', () => {
const mockLogger = new Logger();
getCommitLinesMock = jest
.spyOn(mockLogger, 'log')
.mockImplementation(() => {});
new Person(); // Should call Logger.log() on instantiation.
expect(getCommitLinesMock).toBeCalled();
});
});
一个选项是将 Logger
作为构造函数参数传递,如下所示:
class Person {
constructor(logger: Logger) {
logger.log('created');
}
// ...
}
但是,有没有其他方法不改变构造函数就可以完成测试呢?
您可以使用 jest.mock(moduleName, factory, options),它会自动模拟给定模块的所有导出。
所以你可以做 jest.mock("./Logger")
和 Logger
构造函数及其所有方法将被模拟函数替换(that return undefined
默认情况下),现在您可以监视构造函数及其所有方法的行为。
import Person from "./Person";
import Logger from "./Logger";
jest.mock("./Logger");
describe("Person", () => {
it("calls the Logger constructor on instantiation", () => {
new Person();
expect(Logger).toHaveBeenCalledTimes(1);
});
});
所有模拟函数都有一个特殊的 .mock
属性,其中提供了与模拟函数相关的各种数据,包括模拟构造函数在使用 [=16 调用时创建的实例=].
因此,由 mock Logger
创建的所有实例都保存在 Logger.mock.instances
中,您可以使用它来监视方法调用。
import Person from "./Person";
import Logger from "./Logger";
jest.mock("./Logger");
describe("Person", () => {
it("calls the Logger constructor and the log method on instantiation", () => {
new Person();
expect(Logger).toHaveBeenCalledTimes(1);
const mockLoggerInstance = Logger.mock.instances[0];
const mockLogMethod = mockLoggerInstance.log;
expect(mockLogMethod).toHaveBeenCalledTimes(1);
});
});
给定实例化并使用另一个 class Logger
的 class Person
,如何验证 Logger
的方法何时被调用Person
在下面的例子中被实例化了?
// Logger.ts
export default class Logger {
constructor() {}
log(m: String) {
console.log(m);
// Other operations that are outside testing (e.g., file write).
throw Error('error');
}
}
// Person.ts
import Logger from "./Logger";
export default class Person {
constructor() {
const logger = new Logger();
logger.log('created');
}
// ...
}
// Person.test.ts
import Person from "./Person";
import Logger from "./Logger";
describe('Person', () => {
it('calls Logger.log() on instantiation', () => {
const mockLogger = new Logger();
getCommitLinesMock = jest
.spyOn(mockLogger, 'log')
.mockImplementation(() => {});
new Person(); // Should call Logger.log() on instantiation.
expect(getCommitLinesMock).toBeCalled();
});
});
一个选项是将 Logger
作为构造函数参数传递,如下所示:
class Person {
constructor(logger: Logger) {
logger.log('created');
}
// ...
}
但是,有没有其他方法不改变构造函数就可以完成测试呢?
您可以使用 jest.mock(moduleName, factory, options),它会自动模拟给定模块的所有导出。
所以你可以做 jest.mock("./Logger")
和 Logger
构造函数及其所有方法将被模拟函数替换(that return undefined
默认情况下),现在您可以监视构造函数及其所有方法的行为。
import Person from "./Person";
import Logger from "./Logger";
jest.mock("./Logger");
describe("Person", () => {
it("calls the Logger constructor on instantiation", () => {
new Person();
expect(Logger).toHaveBeenCalledTimes(1);
});
});
所有模拟函数都有一个特殊的 .mock
属性,其中提供了与模拟函数相关的各种数据,包括模拟构造函数在使用 [=16 调用时创建的实例=].
因此,由 mock Logger
创建的所有实例都保存在 Logger.mock.instances
中,您可以使用它来监视方法调用。
import Person from "./Person";
import Logger from "./Logger";
jest.mock("./Logger");
describe("Person", () => {
it("calls the Logger constructor and the log method on instantiation", () => {
new Person();
expect(Logger).toHaveBeenCalledTimes(1);
const mockLoggerInstance = Logger.mock.instances[0];
const mockLogMethod = mockLoggerInstance.log;
expect(mockLogMethod).toHaveBeenCalledTimes(1);
});
});