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

如何使用Jest模拟Mongoose的Query.prototype.exec()方法?

解决Mongoose findById().exec() 单元测试中 exec is not a function 错误

问题出在你当前的mock逻辑不符合Mongoose的实际调用链:findById返回的是Mongoose Query实例,而非直接返回Promise,必须调用该实例的exec()方法才会触发异步查询。你之前用mockResolvedValueOnce让findById直接返回值,导致后续调用.exec()时自然找不到这个方法。

下面是两种可行的解决方案:

方案1:直接模拟带exec方法的Query对象

针对单个测试用例,手动构造一个包含exec方法的mock对象,让findById返回这个对象:

test('find one item by id', async () => {
  // 构造mock Query对象,exec方法返回预期数据
  const mockQuery = {
    exec: jest.fn().mockResolvedValueOnce({ _id: '1234556' })
  };
  // 让findById返回这个mock Query
  jest.spyOn(myMockModel, 'findById').mockReturnValueOnce(mockQuery as any);

  const result = await myService.getMyObjectById('1234556');
  expect(result._id).toBe('1234556');
  // 额外验证exec方法确实被调用
  expect(mockQuery.exec).toHaveBeenCalled();
});

方案2:全局mock Mongoose Query(适合多测试用例复用)

如果多个测试都需要用到Query的exec方法,可以在测试文件顶部全局mock Mongoose的Query类,统一处理链式调用:

// 全局mock Mongoose Query
jest.mock('mongoose', () => {
  const originalMongoose = jest.requireActual('mongoose');
  return {
    ...originalMongoose,
    Query: jest.fn().mockImplementation(() => ({
      exec: jest.fn().mockResolvedValue({})
    }))
  };
});

// 单个测试用例中覆盖exec的返回值
test('find one item by id', async () => {
  const mockResult = { _id: '1234556' };
  const mockExecFn = jest.fn().mockResolvedValueOnce(mockResult);
  
  jest.spyOn(myMockModel, 'findById').mockReturnValueOnce({
    exec: mockExecFn
  } as any);

  const result = await myService.getMyObjectById('1234556');
  expect(result._id).toBe('1234556');
  expect(mockExecFn).toHaveBeenCalledTimes(1);
});

这两种方案都能保留exec()方法,符合Mongoose的官方最佳实践,同时解决测试报错问题。

内容的提问来源于stack exchange,提问作者Koji D'infinte

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 20:55:16