Reputation: 31
I am trying to accomplish mocking the Mongoose save method for all instances of a particular Model during a unit test case (Sinon,Mocha, Chai) using promises. I am using sinon-mongoose and sinon-as-promised per several other examples. I am trying to get to something like this end state of test code:
var expect = require('chai').expect;
var sinon = require('sinon');
require('sinon-as-promised');
require('sinon-mongoose');
/* Mongoose schema+model for User method persist */
var UserModel = require('./models').userModel;
/* code module that will be tested */
var userMethods = require('./user');
/* unit test setup*/
var userModelMock = sinon.mock(UserModel);
/* mock all instances of UserModel saves with a forced error return to test code modules */
userModelMock.expects('save')
.chain('exec')
.rejects('error saving');
/* call code module method for testing that creates new instance of UserModel and receives mocked save error*/
return userMethods.addUser().then(function(result){
expect(result).to.equal(false);
userModelMock.restore();
});
I realize the save method is a per instance method so the above mock doesn't work "globally" or within the called addUser() method under test (addUser() doesn't see the mock and hits the database).
Is there some way to reference the Schema Object or other object property to mock all subsequent instances with out creating custom object wrappers or using other esoteric methods? The last answer on this SO post (not the marked answer) comes closest but it only works for a specific instance of a model: Stubbing a Mongoose model using Sinon
Upvotes: 0
Views: 1181
Reputation: 31
I was able to develop a solution based on the suggestion of @Merott (Github) as described in the following issue discussion for sinon-mongoose (although there is some discussion about manipulating the prototype): https://github.com/underscopeio/sinon-mongoose/issues/7
Essentially I had to add the following code ahead of my save mocks and work off the model prototype:
Object.defineProperty(UserModel.prototype, 'save', {
value: UserModel.prototype.save,
configurable: true,
});
The full code snippet above with the appropriate adjustments:
var expect = require('chai').expect;
var sinon = require('sinon');
require('sinon-as-promised');
require('sinon-mongoose');
/* Mongoose schema+model for User method persist */
var UserModel = require('./models').userModel;
/* code module that will be tested */
var userMethods = require('./user');
/* unit test setup*/
Object.defineProperty(UserModel.prototype, 'save', {
value: UserModel.prototype.save,
configurable: true,
});
var userModelMock = sinon.mock(UserModel.prototype);
/* mock all instances of UserModel saves with a forced error return to test code modules */
userModelMock.expects('save')
.chain('exec')
.rejects('error saving');
/* call code module method for testing that creates new instance of UserModel and receives mocked save error*/
return userMethods.addUser().then(function(result){
expect(result).to.equal(false);
userModelMock.restore();
});
The only issue I saw was post Mock.restore(). If I wanted to return to normal database calls via save(), I saw some issues post mock restore(). Since I am mocking all my database calls it wasn't relevant, but it could be an issue for those needing a mix of mocks and real calls.
Upvotes: 2