How to mock and spy on a mongoose model (or any other object created by a constructor function)

Posted by Gjermund Bjaanes on March 6, 2016

Want to know how to mock and spy on objects created by a constructor?

Allow me to show you!

 

I am currently writing a new back-end for my Extreme Results app using Node.js and Express. I wrote a little about why and how in my previous blog post: Learning Web Dev Series – Part 7: Parse shutting down

I am of course writing unit tests all over the place, and to do that I am using Jasmine, which is the same framework I am using for the client (AngularJS app).

Mongoose

 

I have a MongoDB database, which is being communicated with using “mongoose”.

Mongoose has models which are used for creating objects and querying them. In order to unit test the parts of the application using my mongoose models, I need to mock them out somehow.

I inject the models into my controllers, so what is the actual problem here?

 

Constructors and their baby objects

The problem is that these models are constructors used when creating a new object in the database. The code might look like this:

var outcomeController = function (OutcomeModel) {
    var post = function (req, res) {
        var outcome = new OutcomeModel(req.body); // Creating a new outcome here with the body of the request
        outcome.save(function (error) { ... }); // Saving the outcome here
    };
...

 

I am injecting the model into a controller, which then makes it possible to inject a mock model when unit testing.

But the objects being created are not that easy to spy on with Jasmine.

How can i spy on the objects being created inside the controller?

 

Prototype to the rescue

Turns out that I can spy on the prototype, which makes this fairly easy.

I create my base mock like this in the top of my test file.

OutcomeMock = function () {};
OutcomeMock.prototype.save = function () {};
OutcomeMock.prototype.remove = function () {};
OutcomeMock.prototype.validateSync = function () {};
OutcomeMock.find = function () {};

When I create my controllers in my tests, I just send in the OutcomeMock:

var outcomeController = require('../../controllers/outcomeController')(OutcomeMock);

I can then spy on my outcome created inside the controller like this:

spyOn(OutcomeMock.prototype, 'save');

All the code is available on Github, so if you want to see how I do all my testing, take a look:

 

https://github.com/bjaanes/ExtremeResults-Server


Follow me on Twitter: @gjermundbjaanes