Stubbing a Mongoose model with Sinon
I want to create a stub for the Mongoose save
method in a particular model, so that any instance of my model I create will call the stub instead of the normal Mongoose save
method. My understanding is that the only way to do this is to stub the entire model like this:
var stub = sinon.stub(myModel.prototype);
Unfortunately, this line of code causes my tests to throw the following error:
TypeError: Cannot read property 'states' of undefined
Does anyone know what is going wrong here?
Solution 1:
There are two ways to accomplish this. The first is
var mongoose = require('mongoose');
var myStub = sinon.stub(mongoose.Model, METHODNAME);
If you console log mongoose.Model you will see the methods available to the model (notably this does not include lte option).
The other (model specific) way is
var myStub = sinon.stub(YOURMODEL.prototype.base.Model, 'METHODNAME');
Again, the same methods are available to stub.
EDIT: Some methods such as save are stubbed as follows:
var myStub = sinon.stub(mongoose.Model.prototype, METHODNAME);
var myStub = sinon.stub(YOURMODEL.prototype, METHODNAME);
Solution 2:
Take a look to sinon-mongoose. You can expects chained methods with just a few lines:
sinon.mock(YourModel).expects('find')
.chain('limit').withArgs(10)
.chain('exec');
You can find working examples on the repo.
Also, a recommendation: use mock
method instead of stub
, that will check the method really exists.
Solution 3:
save
is not a method on the model, it's a method on the document (instance of a model). Stated here in mongoose docs.
Constructing documents
Documents are instances of our model. Creating them and saving to the database is easy
Therefore, it will always be undefined if you're using your model to mock a save()
Going along with @Gon's answer, using sinon-mongoose & factory-girl with Account
being my model:
Will not work
var AccountMock = sinon.mock(Account)
AccountMock
.expects('save') // TypeError: Attempted to wrap undefined property save as function
.resolves(account)
Will work
var account = { email: '[email protected]', password: 'abc123' }
Factory.define(account, Account)
Factory.build('account', account).then(accountDocument => {
account = accountDocument
var accountMock = sinon.mock(account)
accountMock
.expects('save')
.resolves(account)
// do your testing...
})