I am writing unit test cases for the following file
//filename: a.js
var amqp = require("amqplib");
class RMQ {
constructor(connectionURI) {
this.URI = connectionURI;
}
async getInstance() {
var connection = await amqp.connect(this.URI);
this.connection = connection;
return connection;
}
}
const RMQ_INSTANCE = new RMQ(process.env.RMQ_URL);
module.exports = {
RMQ_INSTANCE,
};
I am using the instance RMQ_INSTANCE
in below file
// filename: b.js
const { RMQ_INSTANCE } = require("./a");
module.exports.publishEmail = async function(message) {
var connection = await RMQ_INSTANCE.getInstance();
var channel = await connection.createChannel();
var exchange = "some_exchange";
var key = "some_key";
var msg = JSON.stringify(message);
await channel.assertExchange(exchange, "topic", { durable: false });
await channel.publish(exchange, key, Buffer.from(msg));
setTimeout(function () {
connection.close();
}, 500);
}
I am using proxyrequire to mock the RMQ_INSTANCE
in b.js
// filename: b.test.js
var proxyrequire = require("proxyquire").noCallThru();
var sinon = require("sinon");
const { assert } = require("sinon");
class fakeRMQClass {
constructor(connectionURI) {
this.URI = connectionURI;
}
async getInstance() {
var connection = getFakeRMQStub()
return connection;
}
}
var producerTest = function () {
it("producer connection - success test", async function () {
var fakeRMQInstance = new fakeRMQClass("fake_url");
var rmqUtils = proxyrequire("../path/to/b.js", {
"./a": fakeRMQInstance
});
await rmqUtils.publishEmail("fake_msg");
});
afterEach(function () {
sinon.verifyAndRestore();
});
};
describe("test_producer", producerTest);
But I see the mocking is not working correctly. Could anyone please help me to mock this correctly?
CodePudding user response:
Since the RMQ_INSTANCE
is an object, you can stub its methods using sinon.stub(obj, 'method')
, you don't need to use proxyquire
package.
Since you want to test the b
module, the b
module only cares about the interface of the RMQ_INSTANCE
it depends on, and the specific implementation does not matter.
b.js
:
const { RMQ_INSTANCE } = require('./a');
module.exports.publishEmail = async function (message) {
var connection = await RMQ_INSTANCE.getInstance();
var channel = await connection.createChannel();
var exchange = 'some_exchange';
var key = 'some_key';
var msg = JSON.stringify(message);
await channel.assertExchange(exchange, 'topic', { durable: false });
await channel.publish(exchange, key, Buffer.from(msg));
setTimeout(function () {
connection.close();
}, 500);
};
a.js
:
class RMQ {
constructor(connectionURI) {
this.URI = connectionURI;
}
async getInstance() {}
}
const RMQ_INSTANCE = new RMQ(process.env.RMQ_URL);
module.exports = { RMQ_INSTANCE };
b.test.js
:
const sinon = require('sinon');
const { RMQ_INSTANCE } = require('./a');
const { publishEmail } = require('./b');
describe('test_producer', () => {
let clock;
before(() => {
clock = sinon.useFakeTimers();
});
after(() => {
clock.restore();
});
it('producer connection - success test', async () => {
const channelStub = {
assertExchange: sinon.stub().returnsThis(),
publish: sinon.stub(),
};
const connectionStub = { createChannel: sinon.stub().resolves(channelStub), close: sinon.stub() };
sinon.stub(RMQ_INSTANCE, 'getInstance').resolves(connectionStub);
await publishEmail('fake message');
sinon.assert.calledOnce(RMQ_INSTANCE.getInstance);
sinon.assert.calledOnce(connectionStub.createChannel);
sinon.assert.calledWithExactly(channelStub.assertExchange, 'some_exchange', 'topic', { durable: false });
sinon.assert.calledWithExactly(
channelStub.publish,
'some_exchange',
'some_key',
Buffer.from(JSON.stringify('fake message')),
);
clock.tick(500);
sinon.assert.calledOnce(connectionStub.close);
});
});
test result:
test_producer
✓ producer connection - success test
1 passing (10ms)
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 75 | 100 |
a.js | 100 | 100 | 50 | 100 |
b.js | 100 | 100 | 100 | 100 |
----------|---------|----------|---------|---------|-------------------