Reputation: 41
I am using fastify framework for my node.js application and sequelize as an ORM. I am using mocha, chai, and Sinon for unit testing. I have to unit test my controller function. The following is the sample controller function.
// controllers.js;
const service = require('../services');
exports.create = (req, reply) => {
const attributes = req.body;
service.create(attributes)
.then((result) => {
reply.code(201).send(result);
})
.catch((error) => {
reply.send(error);
});
};
and my services file is as follows,
// services.js;
const { Model } = require('../models');
function create(attributes) {
return Model.create(attributes);
}
module.exports = { create };
In the above code, I want to unit test only the 'create' function in controllers.js. The problem is, it should not call the database, since it is unit testing. But the Model.create in service.js file will make a call to the database. How can I unit test controller function only?
Upvotes: 3
Views: 7509
Reputation: 102337
You should stub service.create
method and create mocked req
, reply
objects.
E.g.
controller.js
:
const service = require('./service');
exports.create = (req, reply) => {
const attributes = req.body;
service
.create(attributes)
.then((result) => {
reply.code(201).send(result);
})
.catch((error) => {
reply.send(error);
});
};
service.js
:
const { Model } = require('./models');
function create(attributes) {
return Model.create(attributes);
}
module.exports = { create };
models.js
:
const Model = {
create() {
console.log('real implementation');
},
};
module.exports = { Model };
controller.test.js
:
const controller = require('./controller');
const service = require('./service');
const sinon = require('sinon');
const flushPromises = () => new Promise(setImmediate);
describe('62536251', () => {
afterEach(() => {
sinon.restore();
});
it('should create', async () => {
const mResult = 'success';
sinon.stub(service, 'create').resolves(mResult);
const mReq = { body: {} };
const mReply = { code: sinon.stub().returnsThis(), send: sinon.stub() };
controller.create(mReq, mReply);
await flushPromises();
sinon.assert.calledWith(mReply.code, 201);
sinon.assert.calledWith(mReply.send, 'success');
});
it('should handle error', async () => {
const mError = new Error('network');
sinon.stub(service, 'create').rejects(mError);
const mReq = { body: {} };
const mReply = { code: sinon.stub().returnsThis(), send: sinon.stub() };
controller.create(mReq, mReply);
await flushPromises();
sinon.assert.calledWith(mReply.send, mError);
});
});
unit test result with coverage report:
62536251
✓ should create
✓ should handle error
2 passing (13ms)
---------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
---------------|---------|----------|---------|---------|-------------------
All files | 83.33 | 100 | 60 | 83.33 |
controller.js | 100 | 100 | 100 | 100 |
models.js | 66.67 | 100 | 0 | 66.67 | 3
service.js | 66.67 | 100 | 0 | 66.67 | 4
---------------|---------|----------|---------|---------|-------------------
Upvotes: 2