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

如何修复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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 07:20:37