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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 07:54:06