Creating custom Hamcrest matchers
Published the
In my previous post I introduced Hamcrest4QUnit and how to use matchers to write an assertion.
In this post I'll describe how to create a simple matcher that verify if a value can be divided by a given number and how to test it with QUnit and Hamcrest.
Creating a simple matcher
Matchers are functions that returns a Matcher object. The Matcher class is a generic object that only provides two methods, matches and describeTo and which requires two methods in the constructor argument object. These two methods simply calls two others methods _matches and _describeTo that are not defined in the Matcher class and have to be defined when creating a new matcher. The _matches and _describeTo methods should contains the logic of the Matcher.
Let's create a custom matcher that matches if a value can be divided by a given number.
function divideBy ()
{
return new Matcher({
_matches:function(v,msg){},
_describeTo:function(msg){}
});
}
The code above is the minimal setup for a matcher. The divideBy function return a Matcher object which was initialised with the two concrete functions _matches and _describeTo.
Before starting to go further in our matcher's implementation, we'll write the tests that the implementation will have to pass.
test( "divideBy matcher", function(){
// divideBy take one parameter, a number != 0
assertThat( divideBy, throwsError() );
assertThat( divideBy, throwsError().withArgs( "foo" ) );
assertThat( divideBy, throwsError().withArgs( null ) );
assertThat( divideBy, throwsError().withArgs( 0 ) );
// verify that valid value matches
assertThat( 10, divideBy( 1 ) );
assertThat( 10, divideBy( 2 ) );
assertThat( 10, divideBy( -10 ) );
assertThat( 0, divideBy( 7 ) );
assertThat( 3, divideBy( 1.5 ) );
// verify that invalid value don't matches
assertThat( 10, not( divideBy ( 7 ) ) );
assertThat( 3, not( divideBy ( 2 ) ) );
assertThat( 2, not( divideBy ( 10 ) ) );
assertThat( "foo", not( divideBy ( 10 ) ) );
assertThat( null, not( divideBy ( 10 ) ) );
});
Now it is time to implement the concrete behavior of the matcher.
function divideBy ( divider )
{
// verify that divider parameter is valid
if( isNaN( divider ) || divider == null )
throw "The divider must be a valid number";
else if( divider == 0 )
throw "The divider can't be 0"
// returning a new Matcher object with
// all data and logic
return new Matcher({
// the divider value will become a property
// of our matcher
divider:divider,
// _matches perform the test and return a boolean value
// the msg parameter represent the result message
_matches:function(v,msg){
msg.appendText( "was" ).appendValue( v );
return !isNaN( v ) &&
// value of null is 0 but we don't want it
// to be valid
v != null &&
v % this.divider == 0;
},
// _describeTo setup the message displayed
// in the Expected: section
_describeTo:function(msg){
msg.appendText("a Number which can be divided by")
.appendValue( this.divider );
}
});
}
Now we can run the tests to validate that they all pass:
That's all for today, next time I'll cover how to handle nested matchers.
This post is part of the "Hamcrest For QUnit" series.
Previous post in series : Hamcrest For QUnit
Next post in series : Creating custom Hamcrest matchers 2
Wants to leave a word ?