About Me

me

Coming from graphical arts, and nourished by computer since I was a child, I choose the internet games creation to create the bridge between my two passions.

Learn more

Creating custom Hamcrest matchers

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 :

Next post in series :

Wants to leave a word ?