patternjavascriptMinor
Javascript static and prototype mocking
Viewed 0 times
mockingjavascriptprototypeandstatic
Problem
I'm writing unit-tests for my Node.js/Express application with REST endpoints which retrieve stuff via Mongoose from db. Since I'm testing only route functions I want to mock Mongoose by providing custom request and response functions etc. I also had to mock my Person mongoose schema module with mockery.
Here is my api-endpoint functions:
The important part is that the Person schema can be called in two ways:
Here is my mockery mock for Mongoose schema of Person:
```
function MockPerson(person) {
this.content = {};
for (var k in person) {
if (person.hasOwnProperty(k)) {
this.content[k] = person[k]; //add person's properties here to simulate Mongoose's Object
}
}
}
MockPerson.prototype.find = function(params, callback) {
console.log("mockfind");
return null
};
//Ugly. Note that in JS prototype functions are accessible only from instances and statics only from class.
//Mongoose supports both Person.findOne and var p = new Per
Here is my api-endpoint functions:
/* GET one person */
function getPerson(req, res, next) {
Person.findOne({_id: req.params.id}, function(err, person) {
if (!person) {
res.status(404);
res.json({
message: "ERROR: Person with id: " + req.params.id + " was not found from database."
})
} else {
res.json(person)
}
});
}
/* POST one person */
function postPerson(req, res, next) {
console.log(Person);
var p = new Person(req.body);
p.save(function(err) {
console.log(p);
console.log(Person);
if (err) {
res.status(400);
res.json(err);
}
else {
var r = {
message: "New person created",
person: p
};
res.json(r);
res.status(201);
}
});
}The important part is that the Person schema can be called in two ways:
Person.save(function(){}) //static function
var p = new Person(req.body);
p.save(function(err){}) //instance functionHere is my mockery mock for Mongoose schema of Person:
```
function MockPerson(person) {
this.content = {};
for (var k in person) {
if (person.hasOwnProperty(k)) {
this.content[k] = person[k]; //add person's properties here to simulate Mongoose's Object
}
}
}
MockPerson.prototype.find = function(params, callback) {
console.log("mockfind");
return null
};
//Ugly. Note that in JS prototype functions are accessible only from instances and statics only from class.
//Mongoose supports both Person.findOne and var p = new Per
Solution
You have a couple HTTP return codes here in there in your code, but don't explain what each return code means.
I recommend creating an object of the error codes with descriptive names so you can use those in place of just the plain code; it'll aid your readability greatly.
Here is what I came up with:
Then, you can easily access these codes like this, for example:
Notice how I used all capitals for the naming? Generally across other languages, all capital letters is used for constant values.
From
Typically, the
You wrote it the correct way in
The signature of
I realized that prototype functions are only accessible in instances
of Person and statics only from "class" Person
The line you entered after:
Looks perfectly fine to me. However, do you really need to have a method that can be accessed as static and from an instance?
You say in a comment:
"Mongoose supports...". I don't know much about Mongoose, but if it supports both, can't you choose one?
I recommend creating an object of the error codes with descriptive names so you can use those in place of just the plain code; it'll aid your readability greatly.
Here is what I came up with:
var HTTP_CODES = {
CLIENT = {
NOT_FOUND: 404,
BAD_REQUEST: 400
},
SUCCESS = {
CREATE:201
}
}Then, you can easily access these codes like this, for example:
res.status(HTTP_CODES.CLIENT.NOT_FOUND);Notice how I used all capitals for the naming? Generally across other languages, all capital letters is used for constant values.
From
postPerson,if (err) {
res.status(400);
res.json(err);
}
else { // <----------
var r = {
message: "New person created",
person: p
};
res.json(r);
res.status(201);
}Typically, the
else { will come on the same line as the close } of the preceding if statement.You wrote it the correct way in
getPerson so I don't know why you changed it.function MockPerson(person) {
this.content = {};
for (var k in person) {The signature of
MockPerson should not be indented.I realized that prototype functions are only accessible in instances
of Person and statics only from "class" Person
The line you entered after:
MockPerson.prototype.findOne = MockPerson.findOne = function(params, callback)Looks perfectly fine to me. However, do you really need to have a method that can be accessed as static and from an instance?
You say in a comment:
//Mongoose supports both Person.findOne and var p = new Person(); p.findOne() so we need both prototype and static functions"Mongoose supports...". I don't know much about Mongoose, but if it supports both, can't you choose one?
Code Snippets
var HTTP_CODES = {
CLIENT = {
NOT_FOUND: 404,
BAD_REQUEST: 400
},
SUCCESS = {
CREATE:201
}
}res.status(HTTP_CODES.CLIENT.NOT_FOUND);if (err) {
res.status(400);
res.json(err);
}
else { // <----------
var r = {
message: "New person created",
person: p
};
res.json(r);
res.status(201);
}function MockPerson(person) {
this.content = {};
for (var k in person) {MockPerson.prototype.findOne = MockPerson.findOne = function(params, callback)Context
StackExchange Code Review Q#93263, answer score: 4
Revisions (0)
No revisions yet.