在 Jest 29 中使用 MongoDB:基于 jest-mongodb Preset 的集成测试完整指南
2026/9/19 20:25:35 网站建设 项目流程

在 Jest 29 中使用 MongoDB:基于 jest-mongodb Preset 的集成测试完整指南

【免费下载链接】jestDelightful JavaScript Testing.项目地址: https://gitcode.com/gh_mirrors/je/jest

本篇指南围绕 Jest 官方文档中「Using with MongoDB」一节的实战方案展开:借助@shelf/jest-mongodbpreset,配合 Jest 的 Global Setup/Teardown 与 Async Test Environment 两大 API,你可以在真实 MongoDB 实例上编写端到端风格的集成测试,无需手动管理数据库进程、无需在测试内加载额外依赖。读完本文,你将掌握从安装、配置到编写 CRUD 用例的完整链路,并理解 preset、globalSetup 与 testEnvironment 在底层是如何协同工作的。

为什么 Jest 可以平滑对接 MongoDB

MongoDB 的集成测试天然需要一个真实运行的数据库实例:连接、写入、查询、清理数据,每一个环节都要求数据库在线可用。Jest 为此提供了两项关键 API(见 Configuration.md):

  • globalSetup(string):在全部测试文件运行之前执行一次的钩子,可同步或异步,接收globalConfigprojectConfig两个参数。典型用法是在这里启动内存版 MongoDB(mongod)并把实例句柄挂到globalThis上,供globalTeardown读取与回收(docs/Configuration.md#L855-L879)。
  • globalTeardown(string):在所有测试文件运行结束后执行一次的钩子,用于关闭数据库进程、释放资源(docs/Configuration.md#L890-L902)。
  • testEnvironment(node | jsdom | string):指定测试运行的环境,默认为node,也可指向自定义环境对象(需符合JestEnvironment形状)(docs/Configuration.md#L2014-L2113)。

@shelf/jest-mongodb正是把这三者封装成了一个开箱即用的 preset:它替你写好了启动 mongod 的 setup 脚本、关闭 mongod 的 teardown 脚本,以及注入 MongoDB 连接信息的 testEnvironment。你只需要在配置里声明preset,即可获得完整的测试数据库生命周期管理。

第一步:安装 @shelf/jest-mongodb

@shelf/jest-mongodb以开发依赖形式安装:

npm install --save-dev @shelf/jest-mongodb

安装完成后无需在测试文件里额外加载任何依赖——MongoDB 实例的启动与关闭完全由 preset 内置的 global setup/teardown 脚本接管。

第二步:在 Jest 配置中声明 preset

jest.config.js(或package.jsonjest字段、jest.config.json)中指定 preset:

{ "preset": "@shelf/jest-mongodb" }

Jest 的preset配置项指向一个 npm 包,该包根目录需提供jest-preset.jsonjest-preset.jsjest-preset.cjsjest-preset.mjs文件(见 docs/Configuration.md#L1173-L1212)。@shelf/jest-mongodbjest-preset内部即声明了globalSetupglobalTeardowntestEnvironment三项配置,从而把数据库生命周期全部托管给 Jest。

从源码看,preset 的解析发生在 packages/jest-config/src/normalize.ts 的setupPreset函数中(packages/jest-config/src/normalize.ts#L171-L185):Jest 会基于rootDir解析 preset 模块路径,按扩展名查找jest-preset文件,随后与用户配置进行合并。其对应的配置归一化测试位于 packages/jest-config/src/tests/normalize.test.ts,其中覆盖了 preset 缺失、文件格式非法、依赖缺失、与用户配置合并优先级等场景。这意味着:

  • preset 提供的globalSetup/globalTeardown/testEnvironment会自动生效;
  • 你在自身配置中显式书写的同名配置项可以覆盖 preset 的默认值;
  • 若 preset 包内缺少jest-preset.*文件,Jest 会直接报错并提示(对应 normalize.test.ts 中的校验逻辑)。

第三步:编写使用全局 Mongo 全局变量的测试

preset 生效后,Jest 会在测试环境中注入两个全局变量,可直接在测试代码中读取:

  • globalThis.__MONGO_URI__:MongoDB 实例的连接串;
  • globalThis.__MONGO_DB_NAME__:为本次测试运行准备的数据库名称。

结合官方文档的示例,一个完整的插入与查询用例长这样:

const {MongoClient} = require('mongodb'); describe('insert', () => { let connection; let db; beforeAll(async () => { connection = await MongoClient.connect(globalThis.__MONGO_URI__, { useNewUrlParser: true, useUnifiedTopology: true, }); db = await connection.db(globalThis.__MONGO_DB_NAME__); }); afterAll(async () => { await connection.close(); }); it('should insert a doc into collection', async () => { const users = db.collection('users'); const mockUser = {_id: 'some-user-id', name: 'John'}; await users.insertOne(mockUser); const insertedUser = await users.findOne({_id: 'some-user-id'}); expect(insertedUser).toEqual(mockUser); }); });

要点拆解:

  1. 连接只建立一次:在beforeAll中基于__MONGO_URI__建立连接,并从中取出__MONGO_DB_NAME__对应的数据库句柄,供整个 describe 块复用;
  2. 连接只关闭一次:在afterAll中关闭连接,避免资源泄漏与测试间互相干扰;
  3. 断言语义:写入{_id: 'some-user-id', name: 'John'}后再按_id读回,用toEqual验证文档内容一致;
  4. 无需手工启动数据库__MONGO_URI__指向的内存/临时 MongoDB 实例由 preset 负责启动与销毁,因此测试代码里没有出现任何 mongod 相关逻辑。

深入原理:globalSetup / globalTeardown / testEnvironment 如何协作

为了更透彻地理解 preset 做了什么,可以把文档中提到的机制拆开来看。Jest 官方在globalSetup一节中给出的示例(docs/Configuration.md#L871-L888)展示了手工实现时的核心思路——setup 脚本启动 mongod 并把句柄挂到全局:

module.exports = async function (globalConfig, projectConfig) { console.log(globalConfig.testPathPatterns); console.log(projectConfig.cache); // Set reference to mongod in order to close the server during teardown. globalThis.__MONGOD__ = mongod; };

对应的 teardown 脚本则负责关闭进程:

module.exports = async function (globalConfig, projectConfig) { console.log(globalConfig.testPathPatterns); console.log(projectConfig.cache); await globalThis.__MONGOD__.stop(); };

这里有几点值得注意的边界(官方文档明确标注):

  • globalSetup 中定义的全局变量只能在 globalTeardown 中读取,测试套件内部无法直接访问(docs/Configuration.md#L865)。@shelf/jest-mongodb之所以能让测试拿到__MONGO_URI____MONGO_DB_NAME__,是因为它同时自定义了testEnvironment,在环境初始化阶段把连接信息注入到globalThis——这正是文档开篇把「Global Setup/Teardown」与「Async Test Environment」并列作为前提的原因;
  • 全局钩子只触发一次globalSetup在全部测试文件开始前执行,globalTeardown在全部结束后执行(多项目运行器下,仅当该项目至少运行了一个测试时触发),因此数据库进程在整个测试会话中只启动、销毁各一次,性能开销可控;
  • node_modules 不做转换:Jest 会对 setup 文件本身做代码转换,但不会转换node_modules中的代码(docs/Configuration.md#L867)。

仓库内 e2e/global-setup/setupWithConfig.js 展示了 global setup 接收(globalConfig, projectConfig)两个参数的实际用法,其对应端到端测试位于 e2e/tests/globalSetup.test.ts,可作为理解参数形状与调用时机的参考。

进阶:配置 MongoDB 版本与更多自定义

官方文档的结尾指出:关于MongoDB 版本选择、内存数据库的磁盘/内存限制、是否启用副本集等更细致的配置,需要参考@shelf/jest-mongodb自身的文档(本仓库为只读镜像,不包含该 preset 源码;请以你项目node_modules中实际安装的版本为准)。

jest-preset之上做自定义时,推荐遵循以下模式:

// jest.config.js const {defineConfig} = require('jest'); module.exports = defineConfig({ preset: '@shelf/jest-mongodb', // 覆盖 preset 提供的默认值 testTimeout: 20000, // 可叠加你自己的 setup 文件 setupFilesAfterEnv: ['./jest.setup.js'], });

由于 preset 的配置会与你的显式配置做合并(preset 中定义的moduleNameMappertransform等均会被用户配置覆盖,见 normalize.test.ts 中「merges with options」系列用例),你可以在保留 preset 数据库能力的同时,自由补充项目自身的配置项。

小结

环节你需要做的事背后的机制
安装npm install --save-dev @shelf/jest-mongodb
配置在 Jest 配置中声明preset: '@shelf/jest-mongodb'jest-preset内含globalSetup/globalTeardown/testEnvironment(packages/jest-config/src/normalize.ts 完成解析与合并)
编写测试beforeAll中用globalThis.__MONGO_URI__连接、用globalThis.__MONGO_DB_NAME__取库preset 的 testEnvironment 注入全局变量
生命周期无需手动启动/关闭 mongodglobalSetup启动、globalTeardown关闭(参考 docs/Configuration.md#L855-L902 的手工实现示例)

这套方案的实战价值在于:测试环境完全隔离、不依赖本机预装 MongoDB 服务,同时因为跑在真实数据库上,能覆盖索引、聚合、唯一约束等 mock 难以模拟的数据库行为。需要进一步定制(如指定 MongoDB 版本)时,请查阅你所安装的@shelf/jest-mongodb版本自带文档。

【免费下载链接】jestDelightful JavaScript Testing.项目地址: https://gitcode.com/gh_mirrors/je/jest

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询