sur*_*s02 2 javascript class mocking typescript jestjs
给定一个Person
实例化并使用另一个类的类Logger
,如何验证在下面的示例中实例化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();
});
});
Run Code Online (Sandbox Code Playgroud)
一种选择是作为构造函数参数传递Logger
,如下所示:
class Person {
constructor(logger: Logger) {
logger.log('created');
}
// ...
}
Run Code Online (Sandbox Code Playgroud)
但是,有没有其他方法可以在不改变构造函数的情况下完成测试呢?
您可以使用jest.mock(moduleName,factory,options),它会自动模拟给定模块的所有导出。
因此,您可以jest.mock("./Logger")
这样做,Logger
构造函数及其所有方法将被替换为模拟函数(默认返回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);
});
});
Run Code Online (Sandbox Code Playgroud)
所有模拟函数都有一个特殊的.mock
属性,其中与模拟函数相关的各种数据都可用,包括模拟构造函数在使用new
.
因此,由模拟创建的所有实例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);
});
});
Run Code Online (Sandbox Code Playgroud)