使用 Jest 与 MongoDB 集成测试:jest-mongodb Preset 完整指南
2026/9/18 16:40:42 网站建设 项目流程

使用 Jest 与 MongoDB 集成测试:jest-mongodb Preset 完整指南

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

本篇指南讲解如何在 Jest 测试中平滑接入真实 MongoDB:从 Jest 的 Global Setup/Teardown 与 Async Test Environment 基础机制讲起,到使用官方推荐的@shelf/jest-mongodbPreset 一步完成配置,并附上完整可运行的插入/查询测试用例。读完你就能在自己的项目里为数据访问层编写基于真实 Mongo 实例的集成测试。

为什么需要真实 MongoDB 做集成测试

单元测试通常用 mock 掉数据库客户端,但这无法验证真实的查询语法、索引行为与数据一致性。而直接在测试中启动 MongoDB 又会带来两个问题:数据库实例的生命周期管理,以及每个测试文件的连接复用。Jest 官方为此提供了两个机制,让真实 MongoDB 测试变得“顺滑”:

  • Global Setup/Teardown(globalSetup / globalTeardown):在所有测试文件运行前只执行一次的钩子,天然适合启动mongod进程;全部测试结束后再关闭它。
  • Async Test Environment(testEnvironment):允许使用自定义测试环境,把数据库连接等资源注入到globalThis供测试读取。

基于这两套 API,Jest 可以与 MongoDB 平滑协作。配置层面,docs/MongoDB.md 推荐的做法是直接使用社区维护的@shelf/jest-mongodbPreset——它封装了上述全部所需配置,让你无需手写任何启动/关闭 Mongo 的胶水代码。

方案一:基于 globalSetup / globalTeardown 的原生手动配置

如果你想完全掌控流程,可以先理解底层机制。Configuration.md 中对globalSetup的定义如下:

  • 默认值为undefined
  • 指向一个自定义全局 setup 模块,该模块必须导出一个函数(同步或异步均可);
  • 该函数会在所有测试文件运行之前仅触发一次,并接收两个参数:Jest 的globalConfigprojectConfig

典型的 Mongo 手动方案是:在 setup 中启动mongod进程并保存其引用,在 teardown 中关闭。这与 docs/Configuration.md 中给出的示例模式完全一致(示例中__MONGOD__即 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; };
module.exports = async function (globalConfig, projectConfig) { console.log(globalConfig.testPathPatterns); console.log(projectConfig.cache); await globalThis.__MONGOD__.stop(); };

需要注意的几个行为细节(源自 docs/Configuration.md 的说明):

  • 多项目运行器(multi-project runner)下,某个 project 配置的 globalSetup 只有在至少运行了该 project 的一个测试时才会被触发;
  • 通过globalSetup定义的全局变量只能在globalTeardown中读取,无法在测试套件中直接拿到;
  • 虽然 setup 文件本身会经过代码转换,但 Jest不会转换node_modules中的代码——因为加载转换器(如 babel、typescript)本身就依赖这些模块,这一限制同样适用于globalTeardown

手动方案虽可行,但需要自己处理二进制下载、端口分配、多测试文件间的连接共享等问题,这正是 Preset 方案的价值所在。

方案二:使用 jest-mongodb Preset(推荐)

@shelf/jest-mongodb提供了运行 MongoDB 测试所需的全部配置。相比手写 globalSetup/globalTeardown,你只需要三个步骤。

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

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

同时确保项目里已安装官方 MongoDB 驱动mongodb(测试代码中通过require('mongodb')使用)。

第二步:在 Jest 配置中指定 Preset

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

关于preset配置项,docs/Configuration.md 的说明是:preset 作为 Jest 配置的基底,应指向一个在根目录包含jest-preset.jsonjest-preset.jsjest-preset.cjsjest-preset.mjs文件的 npm 模块。若你同时设置了rootDir,preset 文件的解析将相对于该根目录进行。@shelf/jest-mongodb正是按此规范封装了 preset 文件,将 globalSetup、globalTeardown 与自定义测试环境全部内置。

也可以改用 JS/TS 配置形式(与 docs/Configuration.md 中推荐的写法一致):

const {defineConfig} = require('jest'); module.exports = defineConfig({ preset: '@shelf/jest-mongodb', });
import {defineConfig} from 'jest'; export default defineConfig({ preset: '@shelf/jest-mongodb', });

第三步:编写测试

配置完成后,测试代码中不需要手动加载任何额外的依赖(无需自己引入数据库启动模块),直接通过两个预设注入的全局变量使用数据库:

  • globalThis.__MONGO_URI__:当前测试所用 MongoDB 实例的连接 URI;
  • globalThis.__MONGO_DB_NAME__:当前测试使用的数据库名。

完整的插入与查询测试示例如下(沿用 docs/MongoDB.md 的标准写法):

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); }); });

要点拆解:

  • beforeAll/afterAll负责建立与关闭连接,保证所有用例共享同一连接,避免每个用例重复握手;
  • _id使用固定值'some-user-id',使断言可以精确验证写入与读取的往返一致性;
  • expect(insertedUser).toEqual(mockUser)验证返回文档与插入文档逐字段相等,这正是驱动mongodb原生客户端的真实往返验证。

深入理解:Preset 是如何与 Jest 机制协作的

结合前面两部分内容,可以梳理出@shelf/jest-mongodb与 Jest 内部机制的协作链路:

  1. Jest 读取配置中的preset,加载其根目录下的jest-preset.json(或等价文件),将其中的globalSetupglobalTeardowntestEnvironment等配置合并为最终配置(机制说明见 docs/Configuration.md);
  2. 测试开始前,Jest 执行一次 preset 内置的 globalSetup,启动内存中的mongod实例,并把连接信息挂到globalThis上(即__MONGO_URI____MONGO_DB_NAME__);
  3. 各测试文件运行时,通过全局变量获取 URI 与库名,自行创建/复用MongoClient连接;
  4. 全部测试结束后,preset 内置的 globalTeardown 关闭mongod,进程干净退出。

从配置层面看,这套机制与 docs/Configuration.md 中“globalSetup 定义的变量只能在 globalTeardown 中读取”的限制并不冲突——因为连接信息不是通过 globalSetup 的返回值传递,而是以globalThis全局属性的形式在整个测试生命周期内可用,测试文件也可以读取。

注意事项与最佳实践

  • 无需额外加载依赖:preset 方案下测试文件只需require('mongodb')驱动,数据库启动相关的模块全部由 preset 内部处理(见 docs/MongoDB.md 的说明)。
  • 版本与高级配置:MongoDB 版本选择等更细粒度的配置(如指定 mongod 二进制版本、内存限制等)不在本仓库文档范围内,请以@shelf/jest-mongodb自身文档为准。
  • 连接选项的兼容性:示例中的useNewUrlParseruseUnifiedTopology是较老的 MongoDB 驱动选项,新版驱动已默认启用;若你使用最新版驱动,可以去掉这两个选项。请根据你所安装的mongodb驱动版本判断。
  • 隔离性:每个测试文件共享同一个 Mongo 实例但可使用不同数据库名,必要时可在beforeEach中清理集合数据,避免用例间相互污染。
  • CI 环境:preset 内部启动的是内存态mongod,无需外部数据库服务,适合在 CI 中直接运行;若 CI 机器资源紧张,可参考 preset 文档调整相关参数。

小结

通过 docs/MongoDB.md 给出的三步方案(安装@shelf/jest-mongodb→ 配置preset→ 使用__MONGO_URI__/__MONGO_DB_NAME__编写测试),你可以在不维护任何数据库胶水代码的前提下,获得基于真实 MongoDB 的集成测试能力。其底层正是 Jest 的 globalSetup、globalTeardown 与 testEnvironment 机制——理解了这三者,无论是使用 preset 还是手写方案,都能做到心中有数。

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

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

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

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

立即咨询