Friday, July 18, 2008

Extend JsMock to Support Custom Argument Matcher

I needed some custom argument matching in my mocks today. I am using JSMock for JavaScript mocking and I find it a bit limited when it comes to argument matching. It mostly satisfies my needs but occasionally I need it to be a bit more flexible, generally speaking. Now, what I introduced is not something that xMock frameworks usually have but JavaScript is a dynamic language and some things are simply different compared to "static" languages (OK, I admit, I've used only NMock so far, but I can't be much wrong here).

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.

Monday, July 7, 2008

Firebug Net Panel History Overlay version 0.3.0

New version of the Firebug Net Panel History Overlay is available. This version requires Firebug version 1.2.0b4; that's the latest version at the moment. The previous version of the history add-on was making Firebug to hang; some functions from Firebug that I used changed as well as some of the NetMonitor and NetPanel behaviours so it was causing hang.
Due to behaviour changes it might happen that with new versions of the Firebug I will have to tweak history add-on but will keep close eye on Firebug changes and if required will update the add-on.

Friday, July 4, 2008

Setup Data-Driven Tests in Visual Studio to use Excel

I prefer simplicity of Excel files for my data-driven unit tests in Visual Studio - both 2005 and 2008. However the new test data source wizard is not supporting Excel files so the connection has to be setup manually.
It is not too hard to set it up, all that is required is addition of DataSourceAttribute to your test method:


[TestMethod]
[DeploymentItem("testData.xls")]
[DataSource(“System.Data.Odbc”,
@”Driver={Microsoft Excel Driver (*.xls)};DriverId=790;Dbq=testData.xls;DefaultDir=.”,
“Sheet1$”, DataAccessMethod.Sequential)]

public void SomeTest(){
//some testing
}




DeploymentItemAttribute is there so testData.xls file would be deployed with the test and thus make the test independent of a machine on which it is run. More about using Excel to drive your unit tests with some tips you can find here: Data-Driven Unit Testing using Excel in Visual Studio.