Reputation: 1130
I've a controller called by an Express.js router. The controller itself call mongoose model. I need to unit test the controller without calling the database and independent from the router.
Test probably should test the res.json(err)
and res.json(result)
response.
Page controller:
const pageModel = require('../model/page');
const pageController = {
/**
* Get all pages as a list
*
* @param {*} req
* @param {*} res
* @returns {json} list of pages
*/
getList(req, res) {
pageModel.find({}, (err, result)=>{
if (err) {
res.json(err);
} else {
res.json(result);
}
});
}
};
module.exports = pageController;
Page model:
const mongoose = require('mongoose');
// Page Schema
const pageSchema = new mongoose.Schema({
title: {
type: String,
required: true
},
slug: {
type: String,
required: true,
unique: true
},
content: String,
createdIn: {
type: Date,
default: Date.now
},
updatedIn: {
type: Date,
default: Date.now
}
});
const pageModel = mongoose.model('page', pageSchema);
module.exports = pageModel;
Test:
const chai = require('chai');
const expect = chai.expect;
const mongoose = require('mongoose');
const PageModel = require('../../../../app/page/model/page');
const pageController = require('../../../../app/page/controller/page');
const sinon = require('sinon');
let sandbox = sinon.createSandbox();
describe('Page controller', () => {
describe('getList', () => {
it('should return result as json object', (done) => {
});
});
});
Upvotes: 0
Views: 365
Reputation: 1130
Here is an answer to my question:
First I modified the controller function getList
to send error status
getList(req, res) {
PageModel.find({}, (err, result) => {
if (err) {
res.status(500).end();
} else {
res.json(result);
}
});
}
Now, test will test 2 things. 1- A result which return an instance of "Page" which is json object. 2- Error
Explanation:
1- Create a sinon sandbox
let sandbox = sinon.createSandbox();
2- Mock and define: req, res, error ..etc.
let req = {
body: {
title: 'title',
slug: 'slug',
content: 'content'
}
};
let res = {};
let expectedResult;
let error = new Error({error: 'error message here'});
3- Before each test, spy on res.json and res.status (error) and create the expected result (optional). After each test restore the sandbox.
beforeEach(()=>{
res = {
json: sandbox.spy(),
status: sandbox.stub().returns({end: sandbox.spy()})
};
expectedResult = [{}, {}, {}];
});
afterEach(()=>{
sandbox.restore();
});
4- In test. Stub mongoose.Model
not PageModel
. This way you can be sure that mongoose will not call the database (This is important as we don't do integration test). Then make sure that PageModel
has been called and the controller function return the expected result.
it('should return result/page as json object', (done) => {
sandbox.stub(mongoose.Model, 'find').yields(null, expectedResult);
PageController.getList(req, res);
sinon.assert.calledWith(PageModel.find, {});
sinon.assert.calledWith(res.json, sinon.match.array);
done();
});
it('should return error 500', (done) => {
sandbox.stub(mongoose.Model, 'find').yields(error);
PageController.getList(req, res);
sinon.assert.calledWith(PageModel.find, {});
sinon.assert.calledWith(res.status, 500);
sinon.assert.calledOnce(res.status(500).end);
done();
});
Here is the full code:
const chai = require('chai');
const expect = chai.expect;
const mongoose = require('mongoose');
const PageModel = require('../../../../app/page/model/page');
const PageController = require('../../../../app/page/controller/page');
const sinon = require('sinon');
let sandbox = sinon.createSandbox();
describe('Page controller', () => {
let req = {
body: {
title: 'title',
slug: 'slug',
content: 'content'
}
};
let res = {};
let expectedResult;
let error = new Error({error: 'error message here'});
describe('getList', () => {
beforeEach(()=>{
res = {
json: sandbox.spy(),
status: sandbox.stub().returns({end: sandbox.spy()})
};
expectedResult = [{}, {}, {}];
});
afterEach(()=>{
sandbox.restore();
});
it('should return result/page as json object', (done) => {
sandbox.stub(mongoose.Model, 'find').yields(null, expectedResult);
PageController.getList(req, res);
sinon.assert.calledWith(PageModel.find, {});
sinon.assert.calledWith(res.json, sinon.match.array);
done();
});
it('should return error 500', (done) => {
sandbox.stub(mongoose.Model, 'find').yields(error);
PageController.getList(req, res);
sinon.assert.calledWith(PageModel.find, {});
sinon.assert.calledWith(res.status, 500);
sinon.assert.calledOnce(res.status(500).end);
done();
});
});
});
Please if you find an improvement to this answer feel free to edit the answer or write your own answer
Upvotes: 1