You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 06:25:26