Stopping the mongoose conservation method on the model

I would like to stub the save method available to Mongoose models. Here's a sample model:

 /* model.js */ var mongoose = require('mongoose'); var userSchema = mongoose.Schema({ username: { type: String, required: true } }); var User = mongoose.model('User', userSchema); module.exports = User; 

I have a helper function that will call the save method.

 /* utils.js */ var User = require('./model'); module.exports = function(req, res) { var username = req.body.username; var user = new User({ username: username }); user.save(function(err) { if (err) return res.end(); return res.sendStatus(201); }); }; 

I would like to verify that user.save is called inside my helper function using unit test.

 /* test.js */ var mongoose = require('mongoose'); var createUser = require('./utils'); var userModel = require('./model'); it('should do what...', function(done) { var req = { username: 'Andrew' }; var res = { sendStatus: sinon.stub() }; var saveStub = sinon.stub(mongoose.Model.prototype, 'save'); saveStub.yields(null); createUser(req, res); // because `save` is asynchronous, it has proven necessary to place the // expectations inside a setTimeout to run in the next turn of the event loop setTimeout(function() { expect(saveStub.called).to.equal(true); expect(res.sendStatus.called).to.equal(true); done(); }, 0) }); 

I found var saveStub = sinon.stub(mongoose.Model.prototype, 'save') from here .

Everything is fine, unless I try to add something to my saveStub , for example. with saveStub.yields(null) . If I wanted to simulate the error passed to the save return message with saveStub.yields('mock error') , I get this error:

 TypeError: Attempted to wrap undefined property undefined as function 

Stack tracing is completely useless.

Study i did

I tried to reorganize my model to gain access to the user's base model, as recommended here . This gave me the same error. Here is my code for this attempt:

 /* in model.js... */ var UserSchema = mongoose.model('User'); User._model = new UserSchema(); /* in test.js... */ var saveStub = sinon.stub(userModel._model, 'save'); 

I found that this solution does not work for me at all. Maybe this is because I'm setting up my user model differently?

I also tried Mockery after this guide and this one , but it was much more complicated than I thought it was necessary, and made me question the value of wasting time to isolate db.

I got the impression that all this has to do with the mysterious way mongoose implements save . I read something about this using npm hooks , which makes the save method a slippery thing to stub.

I also heard about mockgoose , although I have not tried this solution yet. Has anyone succeeded in this strategy? [EDIT: it turns out that mockgoose provides a database in memory for ease of setup / stall, but this does not solve the problem of trimming.]

Any understanding of how to solve this problem would be greatly appreciated.

+6
source share
2 answers

Here the final configuration was developed, which uses a combination of synons and ridicule:

 // Dependencies var expect = require('chai').expect; var sinon = require('sinon'); var mockery = require('mockery'); var reloadStub = require('../../../spec/utils/reloadStub'); describe('UNIT: userController.js', function() { var reportErrorStub; var controller; var userModel; before(function() { // mock the error reporter mockery.enable({ warnOnReplace: false, warnOnUnregistered: false, useCleanCache: true }); // load controller and model controller = require('./userController'); userModel = require('./userModel'); }); after(function() { // disable mock after tests complete mockery.disable(); }); describe('#createUser', function() { var req; var res; var status; var end; var json; // Stub `#save` for all these tests before(function() { sinon.stub(userModel.prototype, 'save'); }); // Stub out req and res beforeEach(function() { req = { body: { username: 'Andrew', userID: 1 } }; status = sinon.stub(); end = sinon.stub(); json = sinon.stub(); res = { status: status.returns({ end: end, json: json }) }; }); // Reset call count after each test afterEach(function() { userModel.prototype.save.reset(); }); // Restore after all tests finish after(function() { userModel.prototype.save.restore(); }); it('should call `User.save`', function(done) { controller.createUser(req, res); /** * Since Mongoose `new` is asynchronous, run our expectations on the * next cycle of the event loop. */ setTimeout(function() { expect(userModel.prototype.save.callCount).to.equal(1); done(); }, 0); }); } } 
+3
source

You tried:

 sinon.stub(userModel.prototype, 'save') 

Also, where does the helper function call the test? It looks like you define the function as a utils module, but call it as a method of the controller object. I suppose this has nothing to do with this error message, but it made it difficult to determine when and where the stub was called.

+1
source

Source: https://habr.com/ru/post/983247/


All Articles