Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
easternbloc committed Jan 15, 2012
0 parents commit 360ef9b
Show file tree
Hide file tree
Showing 63 changed files with 7,438 additions and 0 deletions.
42 changes: 42 additions & 0 deletions README.md
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,42 @@
Syringe
=======
Using modules in node is easy however unit testing code that requires modules is a little more tricky. Syringe aims to assist with this problem by providing a handy set of helpers for injection and watching of module methods.

## Turtles all the way down
To properly unit test your code you need mock all the modules and methods your module collaborates with. Ideally you keep going till you hit turtles or at least until you've stubbed every method you use. Take the following example:

var dns = require('dns');
var url = require('url');

module.exports.resolveAddress = function(urlToResolve, callback) {
var urlParsed = url.parse(urlToResolve).hostname;

dns.resolve4(urlParsed, callback);
};

In order to unit test this module properly, you need to mock functions in the dns and url modules. Syringe lets you inject directly over the top of modules or selectively mock the methods in them you're using.

var dns = require('./dns');
var syringe = require('syringe');

var dnsMod = syringe('dns');
var urlMod = syringe('url');

dnsMod.inject('resolve4', function (url, callback) {
callback(null, ['127.0.0.1']);
});

urlMod.inject('parse', function() {
return {hostname: 'www.google.com'};
});

urlMod.wrap('parse', function() {
console.log('yep, that function was called from within the require!');
});

dns.resolveAddress('http://www.google.com/', function(err, result) {
if (err) {
throw new Error(err);
}
console.log('Resolved dns list:', result);
});
8 changes: 8 additions & 0 deletions example/dns.js
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,8 @@
var dns = require('dns');
var url = require('url');

module.exports.resolveAddress = function(urlToResolve, callback) {
var urlParsed = url.parse(urlToResolve).hostname;

dns.resolve4(urlParsed, callback);
}
23 changes: 23 additions & 0 deletions example/dnsExample.js
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,23 @@
var dns = require('./dns');
var syringe = require('../lib/syringe');
var dnsMod = syringe('dns');
var urlMod = syringe('url');

dnsMod.inject('resolve4', function (url, callback) {
callback(null, ['127.0.0.1']);
});

urlMod.inject('parse', function() {
return {hostname: 'www.google.com'};
});

urlMod.wrap('parse', function() {
console.log('yep, that function was called from within the require!');
});

dns.resolveAddress('http://www.google.com/', function(err, result) {
if (err) {
throw new Error(err);
}
console.log('Resolved dns list:', result);
});
1 change: 1 addition & 0 deletions index.js
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./lib/syringe');
75 changes: 75 additions & 0 deletions lib/syringe.js
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,75 @@
var modules = {};

function Syringe(moduleName) {
var moduleCache = {},
module = require(moduleName);

modules[moduleName] = module;

this.inject = function(methodName, method) {
if(module[methodName]) {
this.forceInject(methodName, method);
return this;
} else {
throw new Error(methodName + ' does not exist in the module.');
}
};

this.forceInject = function(methodName, method) {
if(module[methodName]) {
moduleCache[methodName] = module[methodName];
}
module[methodName] = method;
return this;
};

this.restore = function(methodName) {
if(moduleCache[methodName]) {
module[methodName] = moduleCache[methodName];
return this;
} else {
throw new Error(methodName + ' does not exist in the module so cannot be restored.');
}
};

this.wrap = function(methodName, before) {
if (module[methodName] && typeof before === 'function') {
moduleCache[methodName] = module[methodName];

module[methodName] = function() {
before();
return moduleCache[methodName].apply(null, arguments);
}
} else {
throw new Error(methodName + ' does not exist in the module so cannot be wrapped.');
}
};

this.unWrap = function(methodName) {
this.restore(methodName);
};

this.replaceAll = function(replaceModule) {
if (typeof replaceModule === 'object') {
for(var methodName in replaceModule) {
this.inject(methodName, replaceModule[methodName]);
}
} else {
throw new Error(methodName + ' does not exist in the module so cannot be wrapped.');
}
};

this.restoreAll = function(restoreModule) {
for(var method in moduleCache) {
this.restore(method);
};
};
}

module.exports = function(moduleName) {
if (!modules[moduleName]) {
return new Syringe(moduleName);
} else {
return modules[moduleName];
}
};
108 changes: 108 additions & 0 deletions node_modules/.bin/nodeunit

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions node_modules/nodeunit/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions node_modules/nodeunit/.npmignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

60 changes: 60 additions & 0 deletions node_modules/nodeunit/CONTRIBUTORS.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 19 additions & 0 deletions node_modules/nodeunit/LICENSE

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 360ef9b

Please sign in to comment.