My DB Class to test I have a DB class where i encapsulate Mongodb methods to test
import mongodb from 'mongodb';
import dotenv from 'dotenv';
// Comfigure 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;
My Test File My intention is to mock the connection to db then test
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();
});
});
});
When i run the test The two test cases are falling with the following error.
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)
I suspect my issue is starting when I stub the connection to the DB. Please assist
The instantiation of the DBClient
class is executed immediately when the module is referenced. You need to require the ./utils/db
module after stubbing client.connect()
method.
Besides, don't forget to clear the module cache from require.cache
in afterEach
hook.
e.g.
db.js
:
const mongodb = require('mongodb');
class DBClient {
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');
}
});
}
isAlive() {
return this.isClientConnected;
}
}
const dbClient = new DBClient();
module.exports = dbClient;
db.test.js
:
const { expect } = require('chai');
const sinon = require('sinon');
const mongodb = require('mongodb');
describe('DBClient', function () {
afterEach(function () {
sinon.restore();
delete require.cache[require.resolve('./db')];
});
it('should initialize and connect successfully', function (done) {
const connectStub = sinon.stub(mongodb.MongoClient.prototype, 'connect').callsFake(function (cb) {
cb(null); // No Error
});
const dbClient = require('./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) {
const connectStub = sinon.stub(mongodb.MongoClient.prototype, 'connect').callsFake(function (cb) {
cb(new Error('Failed to connect'));
});
const dbClient = require('./db');
process.nextTick(() => {
expect(dbClient.isAlive()).to.be.false;
expect(connectStub.calledOnce).to.be.true;
done();
});
});
});
Test result:
DBClient
Connected to MongoDB
√ should initialize and connect successfully (42ms)
Error encounted while connecting to MongoDB Error: Failed to connect
at MongoClient.<anonymous> (D:\workspace\mrdulin\expressjs-research\src\stackoverflow\78980387\db.test.js:26:7)
at Object.invoke (D:\workspace\mrdulin\expressjs-research\node_modules\sinon\lib\sinon\behavior.js:163:32)
at MongoClient.functionStub (D:\workspace\mrdulin\expressjs-research\node_modules\sinon\lib\sinon\stub.js:39:43)
at Function.invoke (D:\workspace\mrdulin\expressjs-research\node_modules\sinon\lib\sinon\proxy-invoke.js:47:47)
at MongoClient.connect (D:\workspace\mrdulin\expressjs-research\node_modules\sinon\lib\sinon\proxy.js:219:26)
at new DBClient (D:\workspace\mrdulin\expressjs-research\src\stackoverflow\78980387\db.js:16:15)
at Object.<anonymous> (D:\workspace\mrdulin\expressjs-research\src\stackoverflow\78980387\db.js:31:18)
at Module._compile (node:internal/modules/cjs/loader:1198:14)
at Module.m._compile (D:\workspace\mrdulin\expressjs-research\node_modules\ts-node\src\index.ts:1618:23)
at Module._extensions..js (node:internal/modules/cjs/loader:1252:10)
at Object.require.extensions.<computed> [as .js] (D:\workspace\mrdulin\expressjs-research\node_modules\ts-node\src\index.ts:1621:12)
at Module.load (node:internal/modules/cjs/loader:1076:32)
at Function.Module._load (node:internal/modules/cjs/loader:911:12)
at Module.require (node:internal/modules/cjs/loader:1100:19)
at require (node:internal/modules/cjs/helpers:108:18)
at Context.<anonymous> (D:\workspace\mrdulin\expressjs-research\src\stackoverflow\78980387\db.test.js:28:20)
at callFnAsync (D:\workspace\mrdulin\expressjs-research\node_modules\mocha\lib\runnable.js:392:21)
at Test.Runnable.run (D:\workspace\mrdulin\expressjs-research\node_modules\mocha\lib\runnable.js:336:7)
at Runner.runTest (D:\workspace\mrdulin\expressjs-research\node_modules\mocha\lib\runner.js:677:10)
at D:\workspace\mrdulin\expressjs-research\node_modules\mocha\lib\runner.js:801:12
at next (D:\workspace\mrdulin\expressjs-research\node_modules\mocha\lib\runner.js:594:14)
at D:\workspace\mrdulin\expressjs-research\node_modules\mocha\lib\runner.js:604:7
at next (D:\workspace\mrdulin\expressjs-research\node_modules\mocha\lib\runner.js:486:14)
at Immediate._onImmediate (D:\workspace\mrdulin\expressjs-research\node_modules\mocha\lib\runner.js:572:5)
at processImmediate (node:internal/timers:466:21)
√ should fail to connect and isAlive returns false
2 passing (73ms)