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

如何在单函数中Mock多个方法?Jest测试报错排查

解决Jest Mock类时多次mockImplementation覆盖导致方法失效的问题

你遇到的问题核心在于:每次调用mockImplementation都会完全覆盖之前的mock实现,而不是为类追加方法。如果分开三次调用这个方法,只有最后一次的实现会被保留,前两个方法自然不存在,调用时就会抛出TypeError: xxx is not a function。

下面是几种可行的解决方式:

方式一:一次性为类的所有原型方法添加mock

先通过jest.mockmock整个类,再逐个给类的prototype属性赋值mock函数:

// DeliveryService.test.ts
import DeliveryRepository from './DeliveryRepository';
import DeliveryService from './DeliveryService';

// 先mock整个仓库类
jest.mock('./DeliveryRepository');

// 类型断言,方便后续操作mock方法
const MockedDeliveryRepo = DeliveryRepository as jest.MockedClass<typeof DeliveryRepository>;

// 为每个异步方法指定mock实现
MockedDeliveryRepo.prototype.function1 = jest.fn().mockResolvedValue('func1 mock result');
MockedDeliveryRepo.prototype.function2 = jest.fn().mockResolvedValue('func2 mock result');
MockedDeliveryRepo.prototype.function3 = jest.fn().mockResolvedValue('func3 mock result');

test('postDelivery 会依次调用仓库的三个方法', async () => {
  const service = new DeliveryService();
  await service.postDelivery();

  // 验证每个方法都被调用
  expect(MockedDeliveryRepo.prototype.function1).toHaveBeenCalled();
  expect(MockedDeliveryRepo.prototype.function2).toHaveBeenCalled();
  expect(MockedDeliveryRepo.prototype.function3).toHaveBeenCalled();
});

方式二:使用jest.mock的工厂函数一次性定义所有mock方法

直接在jest.mock的回调里返回类的mock实现,一次性包含所有方法:

// DeliveryService.test.ts
// 先mock仓库类,在工厂函数里定义所有实例方法的mock
jest.mock('./DeliveryRepository', () => {
  return jest.fn().mockImplementation(() => ({
    function1: jest.fn().mockResolvedValue('func1 mock result'),
    function2: jest.fn().mockResolvedValue('func2 mock result'),
    function3: jest.fn().mockResolvedValue('func3 mock result'),
  }));
});

import DeliveryRepository from './DeliveryRepository';
import DeliveryService from './DeliveryService';

test('postDelivery 会依次调用仓库的三个方法', async () => {
  const service = new DeliveryService();
  await service.postDelivery();

  // 获取mock的仓库实例
  const repoInstance = DeliveryRepository.mock.instances[0];
  expect(repoInstance.function1).toHaveBeenCalled();
  expect(repoInstance.function2).toHaveBeenCalled();
  expect(repoInstance.function3).toHaveBeenCalled();
});

方式三:单测试用例中修改单个方法的mock实现

如果需要在不同测试用例中调整某个方法的返回值,不需要重新调用mockImplementation,直接修改对应方法的mock即可:

// 全局先mock好所有方法
const MockedDeliveryRepo = DeliveryRepository as jest.MockedClass<typeof DeliveryRepository>;
MockedDeliveryRepo.prototype.function1 = jest.fn().mockResolvedValue('default result');
MockedDeliveryRepo.prototype.function2 = jest.fn().mockResolvedValue('default result');
MockedDeliveryRepo.prototype.function3 = jest.fn().mockResolvedValue('default result');

test('测试function1返回自定义结果', async () => {
  // 仅修改function1的mock实现,其他方法保持默认
  MockedDeliveryRepo.prototype.function1.mockResolvedValue('custom result');
  
  const service = new DeliveryService();
  await service.postDelivery();
  
  expect(MockedDeliveryRepo.prototype.function1).toHaveReturnedWith('custom result');
});

关键注意点

  • 绝对不要多次调用mockImplementation来为类添加多个方法,这会完全覆盖之前的mock内容
  • 优先选择一次性定义所有mock方法的方式,避免覆盖问题
  • 如果需要动态修改mock行为,直接针对单个方法的mock函数进行修改即可

内容的提问来源于stack exchange,提问作者The Blues

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 03:45:39