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

Jest测试Mongoose查询异常:仅首个测试块可执行求排查

问题分析与解决方案

我之前也碰到过几乎一模一样的问题,这大概率是测试隔离没做好加上异步测试的done使用不当导致的,咱们一步步拆解:


核心原因拆解

1. 异步测试的done调用时机完全错误

在你那组未模拟数据的测试里,你把done()直接写在了Model.find()的外面——Jest会认为你这个测试已经执行完成,直接结束测试进程,而find的回调函数还没来得及触发,自然看不到任何输出。

2. Mockingoose重置不彻底+测试状态残留

虽然你在第一个测试套件的每个test里都调用了mockingoose.resetAll(),但Jest的测试默认会共享模块状态,如果Mongoose的Model实例在测试之间没有被完全重置,前一个测试的mock状态会残留到下一个测试,导致后续的mock配置无法生效,最终返回undefined。

另外,如果测试中没有正确处理Mongoose的连接状态(比如多个测试共享同一个未清理的连接),也会导致后续查询无法正常执行。


一步步解决问题

1. 修复异步测试的done调用逻辑

对于回调式的Mongoose查询,必须把done()放在回调函数内部,确保Jest等待异步操作完成后再结束测试:

// 修正后的未模拟数据测试套件
test('首次查询', (done) => {
  Model.find({}, (err, doc) => {
    console.log(err, doc); // 现在能正常输出结果
    done(); // 把done放在回调里,告诉Jest测试真正完成了
  });
})

test('第二次查询', (done) => {
  Model.find({}, (err, doc) => {
    console.log(err, doc); // 现在会正常触发输出
    done();
  });
})

2. 用钩子函数确保Mockingoose的完全隔离

建议用Jest的beforeEach钩子统一处理mock重置,避免手动重置遗漏,同时尽量用async/await替代done(Jest会自动处理异步测试完成,减少出错概率):

// 优化后的第一个测试套件
beforeEach(() => {
  mockingoose.resetAll(); // 每个测试开始前都重置所有mock状态
});

test('首次查询', async () => {
  mockingoose(Model).toReturn({ name: 'asd' });
  const doc = await Model.find({});
  console.log(doc); // 输出正确值
});

test('第二次查询', async () => {
  mockingoose(Model).toReturn({ name: 'asd' });
  const doc = await Model.find({});
  console.log(doc); // 现在也能输出正确值了
});

3. 处理Mongoose连接的隔离(针对真实数据库测试)

如果你的测试是连接真实数据库而非完全mock,建议在每个测试前后清理连接状态,保证每个测试都有干净的环境:

afterEach(async () => {
  await mongoose.disconnect(); // 每个测试结束后断开连接
});

beforeEach(async () => {
  await mongoose.connect('mongodb://localhost/test'); // 每个测试开始前重新连接
});

本质上就是要保证每个测试都是完全独立的:不管是mock状态、数据库连接还是异步操作的完成时机,都要做好隔离和正确的异步处理,这样后续的测试就能正常执行了。

内容的提问来源于stack exchange,提问作者Gergő Horváth

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:37:24