Tuesday, August 30, 2011

A Mockito catch

Suppose we have such classes and interfaces

public class AddOrganizationAction implements Action {}
public class AddPersonToOrganizationAction implements Action {}


public interface DispatchAsync {
     void execute( Action action, AsyncCallback callback );
}


We're using the best mocking framework ;) Suppose we want to verify that code under test will call execute() with proper Action - AddOrganizationAction.
I found that many developers (including me!) check such condition with

verify(async).execute(any(AddOrganizationAction.class), any(AsyncCallback.class));

In such case AsyncCallback is not important for us. We just want to ensure that AddOrganizationAction will be passed. We run test and it's green. But suddenly if we put the code below into test it will be green too!

verify(async).execute(any(AddPersonToOrganizationAction .class), any(AsyncCallback.class));

Why? Because any() matcher doesn't check the instance of passed object to be equal to declared class (AddOrganizationAction in this case). Any() checks if passed object conforms to method signature. In this case any Action's child will do. And we have an erroneous test!
The proper matcher we'd like to use is isA() matcher that checks if passed object is instance of declared class (which means instance of class or it's children).

So the proper test should contain

verify(async).execute(isA(AddOrganizationAction.class), any(AsyncCallback.class));

Go now and search for any() usages and think about changing it to isA(). In 1 of 10 cases whenever I change all tests in a testcase to isA() usage, I find an error in implementation of logic under test. Luckily I know the catch and now you do :)

Ok. It's not really a catch but ignorance of all us developers that we don't read entire documentantation :)

1 comment:

  1. Many thanks, I wasn't using it the proper way either!

    Good to know

    ReplyDelete