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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 00:05:17