Jest中如何在模块导入前定义环境变量适配MongoMemoryServer测试?
解决方案
你的问题根因为../Device模块的顶层逻辑会在导入时立刻执行,而ES模块静态导入的优先级远高于测试钩子、顶层await的执行时机,所以环境变量还没赋值就已经触发了连接创建逻辑,你的populate使用方式没有问题,生产环境可用就证明了该逻辑的正确性。
方案1:测试侧改用动态导入(无需修改业务代码)
不需要在测试文件顶部静态导入../Device,先完成MongoMemoryServer的启动和环境变量赋值后,再用ES动态导入语法加载模块即可:
// 测试文件示例(以jest为例) describe('Device 模块单元测试', () => { let DeviceFromDb1; let mongoServer; beforeAll(async () => { // 清理之前的模块缓存,避免多次测试复用旧模块 jest.resetModules(); // 启动内存Mongo并设置环境变量 mongoServer = await MongoMemoryServer.create(); process.env.MONGODB_URI = mongoServer.getUri(); process.env.ADMINDB = 'test_admin_db'; // 动态导入Device模块 const deviceModule = await import('../Device'); DeviceFromDb1 = deviceModule.DeviceFromDb1; }); afterAll(async () => { await mongoServer.stop(); }); // 后续测试正常使用DeviceFromDb1即可 test('测试逻辑', () => { expect(DeviceFromDb1).toBeDefined(); }) })
方案2:重构Device模块初始化逻辑(长期更健壮)
将原本顶层执行的连接创建、模型初始化逻辑封装成可调用的函数,避免导入时立刻执行,生产和测试场景都可以自主控制初始化时机:
// ../Device.ts 修改后代码 import mongoose from 'mongoose'; export const initDeviceModels = () => { const conn = mongoose.createConnection( process.env.MONGODB_URI + '/' + process.env.ADMINDB ); const adminDbModel = getAdminModel(conn); // 原有Schema定义逻辑保持不变,ref仍然绑定adminDbModel const DeviceSchema = new mongoose.Schema({ // 你的字段定义 adminRef: { type: mongoose.Schema.Types.ObjectId, ref: adminDbModel } }); const DeviceFromDb1 = conn.model('Device', DeviceSchema); return { DeviceFromDb1, adminDbModel }; }
生产环境在服务启动入口、确认环境变量加载完成后调用初始化函数即可,测试场景同理:先启动MongoMemoryServer设置环境变量,再调用initDeviceModels()拿到需要的模型。
内容的提问来源于stack exchange,提问作者xiaokeliu666
相关产品推荐
相关产品推荐

