Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stubbing a Mongoose model using Sinon

I am trying to stub the mongoose dependency used in this object:

var Page = function(db) {

    var mongoose = db || require('mongoose');

    if(!this instanceof Page) {
        return new Page(db);
    }

    function save(params) {
        var PageSchema = mongoose.model('Page');

        var pageModel = new PageSchema({
            ...
        });

        pageModel.save();
    }

    Page.prototype.save = save;
}

module.exports = Page;

Using the answer for this question, I've tried doing this:

mongoose = require 'mongoose'
sinon.stub mongoose.Model, 'save'

But I got the error:

TypeError: Attempted to wrap undefined property save as function

I also tried this:

sinon.stub PageSchema.prototype, 'save'

And then I got the error:

TypeError: Should wrap property of object

Can anyone help with this? What am I doing wrong?

like image 226
thitemple Avatar asked May 24 '13 04:05

thitemple


People also ask

How do you mock a function in Sinon?

You must call mock() on an object. To complete the test, you must call the verify() function to check that all the mock's expectations were met.

What is the difference between a mongoose schema and model?

A Mongoose schema defines the structure of the document, default values, validators, etc., whereas a Mongoose model provides an interface to the database for creating, querying, updating, deleting records, etc.

Does Mongoose model create collection?

Mongoose by default does not create any collection for the model in the database until any documents are created. The createCollection() method is used to create a collection explicitly.

Which Mongoose method is used to connect to the database?

You can connect to MongoDB with the mongoose.connect() method. mongoose.connect('mongodb://localhost:27017/myapp'); This is the minimum needed to connect the myapp database running locally on the default port (27017). If connecting fails on your machine, try using 127.0.0.1 instead of localhost .


2 Answers

I've analysed mongoose source and don't think this is possible. Save function is not defined on model, but dynamically generated by hooks npm which enables pre/post middleware functionality.

However, you can stub save on instance like this:

page = new Page();
sinon.stub(page, 'save', function(cb){ cb(null) })

UPDATE: Stubbing out pageModel

First, you need to make pageModel accessible by setting it as own property of Page (this.pageModel = xxx). Then, you can stub it like shown bellow:

mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');
mongoose.set('debug', true);

schema = new mongoose.Schema({title: String});
mongoose.model('Page', schema);


var Page = function(db) {

  var mongoose = db || require('mongoose');

  if(!this instanceof Page) {
    return new Page(db);
  }

  var PageSchema = mongoose.model('Page');
  this.pageModel = new PageSchema();

  function save(params, cb) {
    console.log("page.save");
    this.pageModel.set(params);
    this.pageModel.save(function (err, product) {
      console.log("pageModel.save");
      cb(err, product);
    });
  }

  Page.prototype.save = save;
};


page = new Page();

sinon = require('sinon');
sinon.stub(page.pageModel, 'save', function(cb){
  cb("fake error", null);
});

page.save({ title: 'awesome' }, function (err, product) {
  if(err) return console.log("ERROR:", err);
  console.log("DONE");
});
like image 144
Milovan Zogovic Avatar answered Sep 20 '22 12:09

Milovan Zogovic


I recommend you to use mock instead of stub, that will check the method really exists on the original object.

var page = new Page();

// If you are using callbacks, use yields so your callback will be called
sinon.mock(page)
  .expects('save')
  .yields(someError, someResult);

// If you are using Promises, use 'resolves' (using sinon-as-promised npm) 
sinon.mock(page)
  .expects('save')
  .resolves(someResult);

Take a look to sinon-mongoose. You can expects chained methods (on both, Mongoose Models and Documents) with just a few lines (there are working examples on the repo).

like image 45
Gon Avatar answered Sep 18 '22 12:09

Gon