To use JSMock you need only jsmock.js. The only change required in the original code is in __delegateMatching method of the ArgumentMatcher, changes are marked red:
__delegateMatching: function(expected, actual) {
if( expected == null ) {
return this.__match( expected, actual );
}
else if( expected.constructor == TypeOf ) {
return this.__match(expected.type, actual.constructor);
}
else if( expected.constructor == Array ) {
return this.__matchArrays(expected, actual);
}
else if( expected.constructor == CustomMatch){
if(!expected.match){
throw new Error("Custom matcher not available");
}
return expected.match(expected.object, actual);
}
else {
return this.__match(expected, actual);
}
}
So that was just one added if clause. All I am saying there is if the expected argument is of CustomMatch then use its custom matcher method instead of original matching logic. There is of course the implementation of CustomMatch that is required:
function CustomMatch(object){
this.object = object;
this.Using = function(customMatcher){
if(typeof(customMatcher) != 'function'){
throw new Error("Can only take constructors");
}
this.match = customMatcher;
return this;
}
}
CustomMatch.Match = function(object){
return new CustomMatch(object);
}
Usage is simple, as one of the expected arguments use something like the following construct:
CustomMatch.Match(expectedObject).Using(customMatchFunction)
Where expectedObject is obviously object that you want to match to the actual argument and the customMatchFunction is the function to use for custom matching, it expects two arguments and returns boolean. So usage might look something like this:var expectedObject = { fieldOne : 1, fieldTwo : 2 };
var customMatchFunction(expected, actual){
return expected.fieldOne == actual.fieldOne && expected.fieldTwo == actual.fieldTwo;
};
someMock.expects().someMethod(CustomMatch.Match(expectedObject).Using(customMatchFunction));
In your custom matching function you can basically do whatever you want, you could use closure and ignore expected object, or extend the CustomMatch to support something like this: CustomMatch.Use(function(actual){ return actual.fieldOne == 1 && actual.fieldTwo == 2;});
If you are using object literals or duck typing this kind of mock functionality might come handy.
That is something you don't have in C# or Java, C# 3.0 comes closest to object literals with anonymous types but they are by far of less usability, and they have nothing close to duck typing.
I hope you find this small extension justified and, more importantly, useful.
Comments