如何用 Jest 模拟 MongoDB ( mongoClient )

我有一个 DBManager 类可以连接到 mongoClient

import { MongoClient } from 'mongodb';

class DBManager {
  private url = process.env.MONGODB_URL;

  private _connection: MongoClient;

  constructor() {
    this._connection = null;
  }
  get connection() {
    return this._connection;
  }

  async start() {
    if (!this._connection) {
      this._connection = await MongoClient.connect(this.url);
    }
  }
}

export default new DBManager();

我这样称呼这个类

await DBManager.start();
const db = DBManager.connection.db(); 

当我尝试模拟时出现此错误:

Received: [TypeError: db_manager_1.default.connection.db is not a function]

这是如何模拟我使用的方法:

  DBManager.start = jest.fn().mockResolvedValue(() => ({
      connection: jest.fn().mockReturnThis(),
      db: jest.fn().mockResolvedValue({success: true})
    }));

谢谢..

stack overflow How To Mock MongoDB ( mongoClient ) With Jest
原文答案
author avatar

接受的答案

You can use jest.spyOn(object, methodName, accessType?) to mock DBManager.start() method and DBMananger.connection getter.

E.g.

dbManager.ts:

import { MongoClient } from 'mongodb';

class DBManager {
  private url = process.env.MONGODB_URL || '';

  private _connection: MongoClient | null;

  constructor() {
    this._connection = null;
  }
  get connection() {
    return this._connection;
  }

  async start() {
    if (!this._connection) {
      this._connection = await MongoClient.connect(this.url);
    }
  }
}

export default new DBManager();

main.ts:

import DBManager from './dbManager';

export async function main() {
  await DBManager.start();
  const db = DBManager.connection!.db();
  db.collection('users');
}

main.test.ts:

import { main } from './main';
import DBManager from './dbManager';
import { Db, MongoClient } from 'mongodb';

describe('68888424', () => {
  afterEach(() => {
    jest.restoreAllMocks();
  });
  test('should pass', async () => {
    const mockDbInstance = ({
      collection: jest.fn(),
    } as unknown) as Db;
    const mockDb = jest.fn(() => mockDbInstance);
    jest.spyOn(DBManager, 'start').mockResolvedValueOnce();
    jest.spyOn(DBManager, 'connection', 'get').mockReturnValue(({ db: mockDb } as unknown) as MongoClient);
    await main();
    expect(DBManager.start).toBeCalledTimes(1);
    expect(DBManager.connection!.db).toBeCalledTimes(1);
    expect(mockDbInstance.collection).toBeCalledWith('users');
  });
});

test result:

 PASS  examples/68888424/main.test.ts (8.621 s)
  68888424
    ✓ should pass (5 ms)

--------------|---------|----------|---------|---------|-------------------
File          | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
--------------|---------|----------|---------|---------|-------------------
All files     |      75 |       50 |      50 |      75 |                   
 dbManager.ts |   57.14 |       50 |   33.33 |   57.14 | 12-17             
 main.ts      |     100 |      100 |     100 |     100 |                   
--------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        9.532 s

答案:

作者头像

You can use a real MongoDB server to use in tests with the package mongodb-memory-server.

So in your case, you just need to do:

import { MongoMemoryServer } from '../index';

describe('Single MongoMemoryServer', () => {
  let con;
  let mongoServer;

  beforeAll(async () => {
    mongoServer = await MongoMemoryServer.create();
    process.env.MONGODB_URL = mongoServer.getUri();
  });

  afterAll(async () => {
    if (con) {
      await con.close();
    }
    if (mongoServer) {
      await mongoServer.stop();
    }
  });

  it('DBManager connection', async () => {
    await DBManager.start();
    const db = DBManager.connection.db();
    // ...
});