说明如何在模拟类上断言方法调用



我想模拟一个类的实现,但随后执行断言这些方法在我的测试中已被调用。

下面的结果是:

Error: expect(jest.fn()).toHaveBeenCalled()
Expected number of calls: >= 1
Received number of calls:    0

我假设这里不工作的是我在测试文件中对const service = new Service();的调用正在创建模拟的新实例。

我如何模拟类,但确保在测试的其他地方实例化时返回相同的实例?

// ./service.ts
class Service {
getNothing() {
return null;
}
}
export { Service };
// ./controller.ts
import { Service } from './service';
export default async (): Promise<void> => {
const service = new Service();
console.log(`result: ${service.getNothing()}`);
};
// ./example.test.ts
import { Service } from './service';
import controller from './controller';
jest.mock('./service', () => {
return {
Service: jest.fn().mockImplementation(() => {
return {
getNothing: jest.fn(),
};
}),
};
});
describe('example test', () => {
test('example', async () => {
const service = new Service();
await controller();
expect(service.getNothing).toHaveBeenCalled();
});
});

看起来您正在多次调用模拟构造函数,并返回模拟对象的几个不同实例。这意味着expect(service.getNothing)引用的方法与控制器中创建的service.getNothing引用的方法不同。

相反,您需要确保使用相同的函数模拟getNothing的所有实例。幸运的是,这很容易做到:

// ./example.test.ts
import { Service } from './service';
import controller from './controller';
// create our mock to assert on later
const mockedGetNothing = jest.fn();
jest.mock('./service', () => {
return {
Service: jest.fn().mockImplementation(() => {
return {
// return the same mock function for all instances of the module
getNothing: mockedGetNothing,
};
}),
};
});
describe('example test', () => {
test('example', async () => {
const service = new Service();
await controller();
// assert on the mocked function
expect(mockedGetNothing).toHaveBeenCalled();
});
});

请注意,jest将自动将所有模块模拟代码提升到文件的顶部,在任何导入之前,由于模块模拟在幕后工作的方式。如果模拟使用测试文件中定义的变量,这可能会导致问题,尽管据我所知,任何名称以mock开头的变量也应该被提升。

最新更新