Jest中Mock类后如何断言方法调用?解决实例不一致问题
问题:Mock类时实例不一致导致断言失败
测试出现如下报错:
Error: expect(jest.fn()).toHaveBeenCalled() Expected number of calls: >= 1 Received number of calls: 0
我想要Mock一个类的实现,随后在测试中对其方法的调用情况进行断言,但出现了上述问题。推测原因是测试文件中执行const service = new Service();时创建了新的Mock实例,而控制器中实例化的是另一个独立实例。请问如何Mock类,才能确保测试中其他地方实例化该类时返回同一个实例?
相关代码如下:
service.ts
// ./service.ts class Service { getNothing() { return null; } } export { Service };
controller.ts
// ./controller.ts import { Service } from './service'; export default async (): Promise<void> => { const service = new Service(); console.log(`result: ${service.getNothing()}`); };
example.test.ts(原测试代码)
// ./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(); }); });
解决方案
问题核心在于当前的Mock实现每次调用new Service()都会生成全新的实例对象,导致测试代码里创建的实例和控制器内部创建的实例不是同一个,自然无法断言到方法调用。
要让Mock类始终返回同一个实例,只需要提前创建好Mock实例,让mockImplementation每次都返回这个固定实例即可。修改后的测试代码如下:
// ./example.test.ts import { Service } from './service'; import controller from './controller'; // 提前创建固定的Mock实例 const mockServiceInstance = { getNothing: jest.fn(), }; jest.mock('./service', () => { return { // 让Service的构造函数始终返回同一个Mock实例 Service: jest.fn().mockImplementation(() => mockServiceInstance), }; }); describe('example test', () => { test('example', async () => { await controller(); // 直接断言提前创建的mock实例的方法调用 expect(mockServiceInstance.getNothing).toHaveBeenCalled(); }); });
也可以简化写法,利用jest.fn().mockReturnValue直接返回固定实例:
// ./example.test.ts import { Service } from './service'; import controller from './controller'; const mockServiceInstance = { getNothing: jest.fn(), }; jest.mock('./service', () => { return { Service: jest.fn().mockReturnValue(mockServiceInstance), }; }); describe('example test', () => { test('example', async () => { await controller(); expect(mockServiceInstance.getNothing).toHaveBeenCalled(); }); });
这样修改后,不管是测试代码里还是控制器里调用new Service(),拿到的都是同一个mockServiceInstance实例,就能正确断言方法的调用情况了。
内容的提问来源于stack exchange,提问作者ayala
相关产品推荐
相关产品推荐

