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

Mock MongoDB连接后测试用例全部失败,请求技术协助

问题排查:MongoDB DBClient测试用例全部失败

问题背景

封装了用于MongoDB操作的DBClient类,使用Sinon框架Mock连接功能编写测试用例,但运行时两个测试用例均失败,断言结果不符合预期,怀疑Mock连接环节存在问题。

待测试的DBClient类

import mongodb from 'mongodb';
import dotenv from 'dotenv';

// Configure dotenv
dotenv.config();

// eslint-disable-next-line no-unused-vars
class DBClient {
  /** 
  * Creates a new DBclient instance.
  */
  constructor() {
    const host = process.env.DB_HOST || 'localhost';
    const port = process.env.DB_PORT || 27017;
    const database = process.env.DB_DATABASE || 'files_manager';

    const dbUri = `mongodb://${host}:${port}/${database}`;
    this.client = new mongodb.MongoClient(dbUri, {
      useNewUrlParser: true,
      useUnifiedTopology: true,
    }); 

    this.isClientConnected = false;
    this.client.connect((err) => {
      if (err) {
        console.error('Error encounted while connecting to MongoDB', err);
      } else {
        this.isClientConnected = true;
        console.log('Connected to MongoDB');
      }   
    }); 
  }

  /** 
  * check the status of the connection to MongoDB
  * @returns {boolean}
  */
  isAlive() {
    return this.isClientConnected;
  }
}

const dbClient = new DBClient();
module.exports = dbClient;

测试代码

const { expect } = require('chai');
const sinon = require('sinon');
const mongodb = require('mongodb');
const dbClient = require('../utils/db');

describe('DBClient', function() {
  afterEach(function() {
    // Automatically restore all stubs after each test
    sinon.restore();
  }); 

  it('should initialize and connect successfully', function(done) {
    const connectStub = sinon.stub(mongodb.MongoClient.prototype, 'connect').callsFake(function(cb) {
      cb(null); // No Error
    });  
    // Wait for the next tick to allow the callback to execute
    process.nextTick(() => {
      expect(dbClient.isAlive()).to.be.true;
      expect(connectStub.calledOnce).to.be.true;
      done();
    }); 
  }); 
  
  it('should fail to connect and isAlive returns false', function(done) {
    // Stub the connect method to simulate a connection failure
    const connectStub = sinon.stub(mongodb.MongoClient.prototype, 'connect').callsFake(function(cb) {
      cb(new Error('Failed to connect')); 
    }); 

    process.nextTick(() => {
      expect(dbClient.isAlive()).to.be.false;
      expect(connectStub.calledOnce).to.be.true();
      done();
    }); 
  }); 
});

测试报错信息

DBClient
    1) should initialize and connect successfully
    2) should fail to connect and isAlive returns false


  0 passing (20ms)
  2 failing

  1) DBClient
       should initialize and connect successfully:

      Uncaught AssertionError: expected false to be true
      + expected - actual

      -false
      +true
      
      at /root/alx-files_manager/test/connectToMongoDb.test.js:18:39
      at processTicksAndRejections (node:internal/process/task_queues:77:11)

  2) DBClient
       should fail to connect and isAlive returns false:

      Uncaught AssertionError: expected false to be true
      + expected - actual

      -false
      +true
      
      at /root/alx-files_manager/test/connectToMongoDb.test.js:32:43
      at processTicksAndRejections (node:internal/process/task_queues:77:11)

问题根源与修复方案

核心问题

测试文件中,require('../utils/db')会立即执行DBClient的构造函数创建实例,此时Sinon的Stub还未生效,实际的MongoClient.connect已经被调用,后续的Stub对已创建的client实例没有作用,导致断言失败。另外第二个测试用例中,expect(connectStub.calledOnce).to.be.true();多了括号,属于语法错误。

修复后的测试代码

const { expect } = require('chai');
const sinon = require('sinon');
const mongodb = require('mongodb');

describe('DBClient', function() {
  let dbClient;

  afterEach(function() {
    sinon.restore();
  }); 

  it('should initialize and connect successfully', function(done) {
    // 先Stub MongoClient的connect方法
    const connectStub = sinon.stub(mongodb.MongoClient.prototype, 'connect').callsFake(function(cb) {
      cb(null); // 模拟成功连接
    });  

    // 清除模块缓存后重新导入,确保实例使用Stub后的方法
    delete require.cache[require.resolve('../utils/db')];
    dbClient = require('../utils/db');

    process.nextTick(() => {
      expect(dbClient.isAlive()).to.be.true;
      expect(connectStub.calledOnce).to.be.true;
      done();
    }); 
  }); 
  
  it('should fail to connect and isAlive returns false', function(done) {
    // Stub connect方法模拟连接失败
    const connectStub = sinon.stub(mongodb.MongoClient.prototype, 'connect').callsFake(function(cb) {
      cb(new Error('Failed to connect')); 
    }); 

    // 清除缓存后重新导入实例
    delete require.cache[require.resolve('../utils/db')];
    dbClient = require('../utils/db');

    process.nextTick(() => {
      expect(dbClient.isAlive()).to.be.false;
      expect(connectStub.calledOnce).to.be.true; // 修正语法错误,去掉多余括号
      done();
    }); 
  }); 
});

关键修复点

  1. 延迟导入实例:每个测试用例中先完成Sinon Stub,再通过delete require.cache清除模块缓存,重新导入dbClient,确保实例创建时使用Stub后的MongoClient方法。
  2. 修正断言语法:第二个测试中to.be.true()改为to.be.true,避免调用布尔值导致的错误。
  3. 测试隔离:每个测试用例独立创建实例,避免测试间的状态污染。

内容的提问来源于stack exchange,提问作者rungene

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 13:07:37