如何修复Jest测试中TypeError: db.find(...).toArray is not a function报错
嘿,这个报错的核心原因是你mock的MongoDB查询结构不符合真实的API逻辑。真实场景下,db.find()返回的是一个游标对象,而不是直接返回Promise——游标上的toArray()方法才会返回Promise并解析出数据。你当前的mock让db.find()直接返回了Promise,自然找不到toArray方法啦。
下面一步步给你修正:
1. 修复Mock函数的结构
重新编写functionMock,让它模拟出正确的MongoDB游标结构:
function functionMock(returnValue) { // 模拟游标:find返回的对象包含toArray方法,该方法返回Promise const mockCursor = { toArray: jest.fn(() => Promise.resolve(returnValue)) }; // db对象的find方法返回这个模拟游标 return jest.fn(() => ({ find: jest.fn(() => mockCursor) })); }
这样db.find()会返回带有toArray的游标对象,调用toArray()就能拿到你预设的返回值了。
2. 修正ctx的Mock
你的noteController.find大概率会操作ctx对象(比如设置ctx.body或读取查询参数),单纯用jest.fn()模拟ctx太单薄,需要给它模拟必要的属性:
const ctx = { query: {}, // 如果接口需要查询参数,可以在这里设置对应值 body: null // 用来接收控制器返回的结果 };
3. 优化测试用例的写法
async函数测试里不需要done,直接用await即可,避免回调嵌套的问题:
it('should return note list', async () => { // 给DB.getDb设置返回预设测试数据的mock DB.getDb.mockImplementation(functionMock([{ id: 1, content: 'test note' }])); await noteController.find(ctx); // 验证控制器是否正确设置了ctx.body(根据你的实际业务逻辑调整断言) expect(ctx.body).toBeDefined(); expect(ctx.body.length).toBe(1); // 也可以验证find和toArray方法是否被正确调用 const mockDb = DB.getDb(); expect(mockDb.find).toHaveBeenCalled(); const mockCursor = mockDb.find(); expect(mockCursor.toArray).toHaveBeenCalled(); });
修正后的完整测试代码
'use strict'; const DB = require('../../../../app/databases/mongo'); jest.mock('../../../../app/databases/mongo'); const noteController = require('../../../../app/controllers/note'); // 修正后的mock函数,模拟MongoDB的游标结构 function functionMock(returnValue) { const mockCursor = { toArray: jest.fn(() => Promise.resolve(returnValue)) }; return jest.fn(() => ({ find: jest.fn(() => mockCursor) })); } describe('noteController', () => { describe('note controller', () => { describe('find', () => { it('should return note list', async () => { // 设置mock返回的测试数据 DB.getDb.mockImplementation(functionMock([{ id: 1, content: 'test note' }])); // 模拟ctx对象 const ctx = { query: {}, body: null }; await noteController.find(ctx); // 断言结果符合预期 expect(ctx.body).toBeDefined(); expect(ctx.body).toEqual([{ id: 1, content: 'test note' }]); // 验证mock方法被正确调用 expect(DB.getDb).toHaveBeenCalled(); const mockDbInstance = DB.getDb(); expect(mockDbInstance.find).toHaveBeenCalled(); const mockCursor = mockDbInstance.find(); expect(mockCursor.toArray).toHaveBeenCalled(); }); }); }); });
额外说明
- 如果你的
noteController.find里db.find()带有查询条件,记得在断言mockDbInstance.find的时候传入对应的参数,比如expect(mockDbInstance.find).toHaveBeenCalledWith({ status: 'active' }),这样测试会更严谨。 - 如果你想测试错误场景(比如数据库查询失败),可以让
toArray返回一个rejected的Promise:toArray: jest.fn(() => Promise.reject(new Error('DB error'))),然后用expect(noteController.find(ctx)).rejects.toThrow('DB error')来断言。
内容的提问来源于stack exchange,提问作者Sebastian Hondarza Gonzalez
相关产品推荐
相关产品推荐

