如何使用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
相关产品推荐
相关产品推荐

