如何在Jest中Mock MongoDB(Nest.js场景)
在Jest中Mock MongoDB原生驱动的Nest.js单元测试方案
针对你用MongoDB原生驱动操作数据库的场景,这里提供两种实用的Mock方案,完全不需要连接测试数据库:
方案一:Mock依赖注入的Db实例(推荐)
如果你的服务是通过Nest的依赖注入获取Db实例的(这是Nest推荐的做法),可以直接在测试模块中提供一个Mock的Db对象,覆盖真实的数据库连接。
示例服务代码
// user.service.ts import { Injectable, Inject } from '@nestjs/common'; import { Db } from 'mongodb'; @Injectable() export class UserService { constructor(@Inject('DATABASE_CONNECTION') private db: Db) {} async login(loginData: { email: string }) { const user = await this.db .collection('users') .findOne({ email: loginData.email }); // 后续业务逻辑 return user; } }
测试代码实现
// user.service.spec.ts import { Test, TestingModule } from '@nestjs/testing'; import { UserService } from './user.service'; import { Db } from 'mongodb'; describe('UserService', () => { let service: UserService; let mockCollection: any; let mockDb: Partial<Db>; beforeEach(async () => { // 先Mock collection的findOne方法 mockCollection = { findOne: jest.fn().mockResolvedValue({ _id: '123', email: 'test@example.com', password: 'hashed_password' }) }; // 再Mock Db的collection方法,返回上面的mockCollection mockDb = { collection: jest.fn().mockReturnValue(mockCollection) }; const module: TestingModule = await Test.createTestingModule({ providers: [ UserService, { provide: 'DATABASE_CONNECTION', // 和服务中注入的token一致 useValue: mockDb } ], }).compile(); service = module.get<UserService>(UserService); }); it('查询指定邮箱的用户', async () => { const loginData = { email: 'test@example.com' }; const result = await service.login(loginData); // 验证collection方法被正确调用 expect(mockDb.collection).toHaveBeenCalledWith('users'); // 验证findOne的查询参数正确 expect(mockCollection.findOne).toHaveBeenCalledWith({ email: loginData.email }); // 验证返回结果符合预期 expect(result).toEqual({ _id: '123', email: 'test@example.com', password: 'hashed_password' }); }); it('用户不存在时返回null', async () => { // 临时重写findOne的返回值,模拟用户不存在的场景 mockCollection.findOne.mockResolvedValue(null); const result = await service.login({ email: 'no-exist@example.com' }); expect(result).toBeNull(); }); });
方案二:Mock整个MongoDB模块
如果你的服务是直接通过MongoClient创建连接(不推荐,但如果是这种场景),可以用Jest直接Mock整个mongodb模块。
示例服务代码
// user.service.ts import { Injectable } from '@nestjs/common'; import { MongoClient } from 'mongodb'; @Injectable() export class UserService { private db: any; constructor() { // 直接创建数据库连接 MongoClient.connect('mongodb://localhost:27017').then(client => { this.db = client.db('test_db'); }); } async login(loginData: { email: string }) { const user = await this.db .collection('users') .findOne({ email: loginData.email }); return user; } }
测试代码实现
// user.service.spec.ts import { Test, TestingModule } from '@nestjs/testing'; import { UserService } from './user.service'; import { MongoClient } from 'mongodb'; // Mock整个mongodb模块的MongoClient jest.mock('mongodb', () => ({ MongoClient: { connect: jest.fn().mockResolvedValue({ db: jest.fn().mockReturnValue({ collection: jest.fn().mockReturnValue({ findOne: jest.fn().mockResolvedValue({ _id: '456', email: 'mock@example.com' }) }) }) }) } })); describe('UserService', () => { let service: UserService; beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ providers: [UserService], }).compile(); service = module.get<UserService>(UserService); // 等待构造函数中的异步连接完成 await new Promise(resolve => setTimeout(resolve, 0)); }); it('登录时获取用户数据', async () => { const result = await service.login({ email: 'mock@example.com' }); expect(result).toEqual({ _id: '456', email: 'mock@example.com' }); // 验证连接方法被调用 expect(MongoClient.connect).toHaveBeenCalled(); // 验证collection方法被正确调用 expect(service['db'].collection).toHaveBeenCalledWith('users'); }); });
核心注意事项
- 优先使用依赖注入的方式管理数据库连接,Mock逻辑更清晰,也符合Nest的架构设计。
- 用
jest.fn()创建的Mock函数可以灵活修改返回值,覆盖不同测试场景(比如成功、失败、空结果等)。 - 测试时要验证Mock函数的调用参数和次数,确保业务逻辑的正确性。
内容的提问来源于stack exchange,提问作者Julio Raposo
相关产品推荐
相关产品推荐

