使用 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 的
globalConfig与projectConfig。
典型的 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.json、jest-preset.js、jest-preset.cjs或jest-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 内部机制的协作链路:
- Jest 读取配置中的
preset,加载其根目录下的jest-preset.json(或等价文件),将其中的globalSetup、globalTeardown、testEnvironment等配置合并为最终配置(机制说明见 docs/Configuration.md); - 测试开始前,Jest 执行一次 preset 内置的 globalSetup,启动内存中的
mongod实例,并把连接信息挂到globalThis上(即__MONGO_URI__、__MONGO_DB_NAME__); - 各测试文件运行时,通过全局变量获取 URI 与库名,自行创建/复用
MongoClient连接; - 全部测试结束后,preset 内置的 globalTeardown 关闭
mongod,进程干净退出。
从配置层面看,这套机制与 docs/Configuration.md 中“globalSetup 定义的变量只能在 globalTeardown 中读取”的限制并不冲突——因为连接信息不是通过 globalSetup 的返回值传递,而是以globalThis全局属性的形式在整个测试生命周期内可用,测试文件也可以读取。
注意事项与最佳实践
- 无需额外加载依赖:preset 方案下测试文件只需
require('mongodb')驱动,数据库启动相关的模块全部由 preset 内部处理(见 docs/MongoDB.md 的说明)。 - 版本与高级配置:MongoDB 版本选择等更细粒度的配置(如指定 mongod 二进制版本、内存限制等)不在本仓库文档范围内,请以
@shelf/jest-mongodb自身文档为准。 - 连接选项的兼容性:示例中的
useNewUrlParser与useUnifiedTopology是较老的 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),仅供参考