Me and Adlan Elmurzajev have just published https://npmjs.org/package/a – a javascript mocking framework for nodejs. It’s called a, and is installed by npm . In addition to regular mocking, it can also stub require() – that means you can do proper unit testing by isolating the dependencies. The mocking framework can be used in any JavaScript testing framework.
(The package also has a unit test framework in bdd style – this is not fully documented yet, but you can find examples in this repo: https://bitbucket.org/pure/a_demo . When the test framework is fully documented, I will write a blog post about it.)
Key features
- partial mock (fallback)
- strict mock
- mocking require()
- object mock
- multiple expects / returns
- array expects
- repeats: nTimes or infinite
- verify
- interceptors (whenCalled)
Mocking a function
partial mock
var original = function() {
return 'realValue';
}
var mock = require('a').mock(original);
original = mock;
mock.expect().return('fake');
original(); //returns 'fake'
original(); //returns 'realValue'
strict mock
var original = function() {
return 'realValue';
}
var mock = require('a').mock();
original = mock;
mock.expect().return('fake');
original(); //returns 'fake'
original(); //throws unexpected arguments
strict mock with arguments
var original = function(arg) {
return 'realValue';
}
var mock = require('a').mock();
original = mock;
mock.expect('testValue1').return('fake1');
mock.expect('testValue2').return('fake2');
original('testValue1'); //returns 'fake1'
original('testValue2'); //returns 'fake2'
original(); //throws unexpected arguments
original('foo'); //throws unexpected arguments
strict mock with multiple arguments
var original = function(arg1, arg2) {
return 'realValue';
}
var mock = require('a').mock();
original = mock;
mock.expect('firstArg1', 'secondArg1').return('fake1');
mock.expect('firstArg2', 'secondArg2').return('fake2');
original('firstArg1', 'secondArg1'); //returns 'fake1'
original('firstArg2', 'secondArg2'); //returns 'fake2'
original('foo'); //throws unexpected arguments
original('foo', 'bar'); //throws unexpected arguments
strict mock expecting array
var original = function(array) {
return 'realValue';
}
var mock = require('a').mock();
original = mock;
mock.expectArray(['a','b']).return('fake1');
mock.expectArray(['a','b').return('fake2');
mock.expectArray(['c','d').return('fake3');
original(['a','b']); //returns 'fake1'
original(['a','b']); //returns 'fake2'
original(['c','d']); //returns 'fake3'
original(['a','b']); //throws unexpected arguments
original(['foo', 'bar']); //throws unexpected arguments
strict mock with repeats
var original = function() {
return 'realValue';
}
var mock = require('a').mock();
original = mock;
mock.expect().return('fake').repeat(2);
original(); //returns 'fake'
original(); //returns 'fake'
original(); //throws unexpected arguments
strict mock with infinite repeats
var original = function() {
return 'realValue';
}
var mock = require('a').mock();
original = mock;
mock.expect().return('fake').repeatAny();
original(); //returns 'fake'
original(); //returns 'fake'
original(); //returns 'fake'...
strict mock ignoring arguments
var original = function(arg) {
return 'realValue';
}
var mock = require('a').mock();
original = mock;
mock.expectAnything().return('fake1');
original('someRandomValue'); //returns 'fake1'
original(); //throws unexpected arguments
strict mock with interceptor
var original = function(arg) {
return 'realValue';
}
var mock = require('a').mock();
original = mock;
mock.expect('testValue').whenCalled(onCalled).return('fake1');
function onCalled(arg) {
//arg == 'testValue'
}
original('testValue'); //returns 'fake1'
original(); //throws unexpected arguments
strict mock – verify (fail)
var original = function(arg) {
return 'realValue';
}
var mock = require('a').mock();
original = mock;
mock.expect('testValue1').return('fake1');
mock.expect('testValue2').return('fake2');
original('testValue1'); //returns 'fake1'
mock.verify(); //throws mock has 1 pending functions
strict mock – verify (success)
var original = function(arg) {
return 'realValue';
}
var mock = require('a').mock();
original = mock;
mock.expect('testValue1').return('fake1');
mock.expect('testValue2').return('fake2');
original('testValue1'); //returns 'fake1'
original('testValue2'); //returns 'fake2'
mock.verify(); //returns true
strict mock – advanced scenario
var original = function(arg, callback) {
return 'realValue';
}
var mock = require('a').mock();
original = mock;
mock.expect('testValue').expectAnything().whenCalled(onCalled).return('fake1');
function onCalled(arg,callback) {
//arg == 'testValue'
//callback == foo
}
function foo() {
}
original('testValue', foo); //returns 'fake1'
mock.verify() //returns true
original('testValue',foo); //throws unexpected arguments
Mocking require
expectRequire
var fakeDep = {};
var expectRequire = require('a').expectRequire;
expectRequire('./realDep').return(fakeDep);
require('./realDep'); //returns fakeDep
require('./realDep'); //returns realDep (behaves like a partial mock)
requireMock (compact syntax)
var requireMock = require('a').requireMock;
var fakeDep = requireMock('./realDep'); //returns a strict mock
require('./realDep'); //returns fakeDep
require('./realDep'); //returns realDep
..is equivalent to ..
var mock = require('a').mock();
var expectRequire = require('a').expectRequire;
var fakeDep = mock;
expectRequire('./realDep').return(fakeDep);
require('./realDep'); //returns fakeDep
require('./realDep'); //returns realDep
Mocking an object
partial object mock
function newCustomer(_name) {
var c = {};
c.getName = function ()
{
return _name;
};
return c;
}
var customer = newCustomer('Alfonzo The Real');
var customerMock = mock(customer);
customerMock.getName.expect().return('Johnny Fake');
customer.getName(); //returns Johnny Fake
customer.getName(); //returns Alfonzo The Real
customerMock.verify(); //returns true