title: Stubbing the mongoose save method on a model
body: <p>I would like to stub the <code>save</code> method available to Mongoose models. Here's a sample model:</p>
  
  <pre><code>/* model.js */
  var mongoose = require('mongoose');
  var userSchema = mongoose.Schema({
    username: {
      type: String,
      required: true
    }
  });
  var User = mongoose.model('User', userSchema);
  module.exports = User;
  </code></pre>
  
  <p>I have some helper function that will call the <code>save</code> method.</p>
  
  <pre><code>/* 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);
    });
  };
  </code></pre>
  
  <p>I would like to check that <code>user.save</code> is called inside my helper function using a unit test. </p>
  
  <pre><code>/* 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)
  });
  </code></pre>
  
  <p>I discovered <code>var saveStub = sinon.stub(mongoose.Model.prototype, 'save')</code> from <a href="https://stackoverflow.com/a/11567859/2672869">here</a>.</p>
  
  <p>All is fine unless I try to add something to my <code>saveStub</code>, e.g. with <code>saveStub.yields(null)</code>. If I wanted to simulate an error being passed to the <code>save</code> callback with <code>saveStub.yields('mock error')</code>, I get this error:</p>
  
  <pre><code>TypeError: Attempted to wrap undefined property undefined as function
  </code></pre>
  
  <p>The stack trace is totally unhelpful.</p>
  
  <p><strong>The research I've done</strong></p>
  
  <p>I attempted to refactor my model to gain access to the underlying user model, as recommended <a href="https://stackoverflow.com/a/16734625/2672869">here</a>. That yielded the same error for me. Here was my code for that attempt:</p>
  
  <pre><code>/* in model.js... */
  var UserSchema = mongoose.model('User');
  User._model = new UserSchema();
  
  /* in test.js... */
  var saveStub = sinon.stub(userModel._model, 'save');
  </code></pre>
  
  <p>I found that <a href="https://stackoverflow.com/a/8852257/2672869">this solution</a> didn't work for me at all. Maybe this is because I'm setting up my user model in a different way?</p>
  
  <p>I've also tried Mockery following <a href="http://bulkan-evcimen.com/using_mockery_to_mock_modules_nodejs.html" rel="noreferrer">this guide</a> and <a href="https://stackoverflow.com/questions/22340419/stub-save-instance-method-of-mongoose-model-with-sinon">this one</a>, but that was way more setup than I thought should be necessary, and made me question the value of spending the time to isolate the db.</p>
  
  <p>My impression is that it all has to do with the mysterious way mongoose implements <code>save</code>. I've read something about it using npm <code>hooks</code>, which makes the <code>save</code> method a slippery thing to stub.</p>
  
  <p>I've also heard of <a href="https://www.npmjs.com/package/mockgoose" rel="noreferrer">mockgoose</a>, though I haven't attempted that solution yet. Anyone had success with that strategy? [EDIT: turns out mockgoose provides an in-memory database for ease of setup/teardown, but it does not solve the issue of stubbing.]</p>
  
  <p>Any insight on how to resolve this issue would be very appreciated.</p>