EasyMock IArgumentMatcher

When EasyMock is used to set expectations we might need to specify what parameters are used to call a method on the mock object. An ‘IArgumentMatcher’ is used for this purpose as this section from the EasyMock documentation describes.

Sometimes it is desirable to define own argument matchers. Let’s say that an argument matcher is needed that matches an exception if the given exception has the same type and an equal message. It should be used this way:

 
     IllegalStateException e = new IllegalStateException("Operation not allowed.")
     expect(mock.logThrowable(eqException(e))).andReturn(true);

I wanted to specifically check if the argument matcher matches a parameterized java.util.Set with a certain number of elements in it. This is how I am able to do it.

So here I pass the expected size of the Set as a constructur parameter but I use Generics reflection to get the raw type for comparison. The idea to use an anonymous class in the line

 

   SetReturnTest<ObjectInstance> returnTest = new SetReturnTest<ObjectInstance>( set.size() ){};

to preserve the raw type at run-time is from Neil Gafter.

It does seem that not all raw types are erased in all cases. This is still hard to do and I believe I get Generics wrong in many cases.


package com.monitor.test.suite.mock;

import org.easymock.EasyMock;
import org.easymock.IArgumentMatcher;

import javax.management.ObjectInstance;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Set;



public class SetReturnTest<T> implements IArgumentMatcher {


    /**
     * The expected reflective type of objects in the returned java.util.Set
     */
    Type objectTypeExpected;
    /**
     * The expected size of the returned java.util.Set
     */
    protected int size;
    /**
     * The reflective type of objects in the returned java.util.Set
     */
    protected Type type;

    /**
     * The type and number of the objects in the java.util.Set
     * .
     */
    public SetReturnTest( int size ) {
        /**How many are expected in the java.util.Set?*/
        this.size = size;
        /**
         * The  parameterized type is matched
         * with the actual type expected at run-time.
         *
         */
        ParameterizedType pt =
                    (ParameterizedType) (getClass().getGenericSuperclass());
        type = pt.getActualTypeArguments()[ 0 ];
    }

    /**
     * EasyMock via the static method reportMatcher(IArgumentMatcher matcher), 
     * and return a value so that it may be used inside the call (typically 0, null or false). 
     */
    public Set eqSet( Type type, Set set ) {
        objectTypeExpected = type;
        SetReturnTest<ObjectInstance> returnTest = new SetReturnTest<ObjectInstance>( set.size() ){};
        EasyMock.reportMatcher( returnTest );
        return null;
    }


    /**
     * The actual java.util.Set is compared with the
     * one expected by the mock test. There are unchecked
     * warnings here but this seems to be the best possible attempt.
     */
    public boolean matches( Object actual ) {

        /** Unchecked is a potential problem*/
        @SuppressWarnings("unchecked")
        SetReturnTest setReturnTest = (SetReturnTest) actual;

        if( setReturnTest.size != size ){
            return false;
        }
        Type clazz1 = setReturnTest.type;
        Class clazz2 = (Class)objectTypeExpected;

        boolean match =
                clazz2.isAssignableFrom( (Class)clazz1 );

        return match;
    }

    /**
     * Append a simple error to identify which
     * matcher was used.
     */
    public void appendTo(StringBuffer buffer) {
        buffer.append( "SetReturnTest matcher" );
    }
}

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: