JMock Actions API


I use JMock as my preferred mocking library. Most of the time the expectations I write are pretty simple, indicating that a mock should return this value, or should throw this exception. For example:

mockery.checking(new Expectations() 
 allowing(mockConfiguration).getString(
     "nakedobjects.persistor.adapter-factory",
     PojoAdapterFactory.class.getName());
 will(returnValue(PojoAdapterFactory.class.getName()));
}});

However, I recently needed wrote a little API whereby Injectable components will inject themselves into any objects that declare itself to be aware of that component. For example, we have a SpecificationLoader:

public class SpecificationLoaderImpl
    extends SpecificationLoader
    implements Injectable {
  public void injectInto(Object candidate) {
    if (SpecificationLoaderAware.class.isAssignableFrom(
        candidate.getClass())) {
      SpecificationLoaderAware cast = SpecificationLoaderAware.class.cast(candidate);
      cast.setSpecificationLoader(this);
    }
  }
}

Elsewhere I then have code such as:

specificationLoader.injectInto(someObject);

and don’t have to worry whether someObject is aware of SpecificationLoader or not.

But, what if I have a mock SpecificationLoader? How do I tell it to behave correctly if we call its injectInto() method? In fact, how can I do this for any Injectable component? This is what I came up with:

public final class InjectIntoJMockAction
  implements Action {
  public void describeTo(Description description) {
    description.appendText("inject self");
  }
  // x.injectInto(y) ---> y.setXxx(x)
  public Object invoke(Invocation invocation) throws Throwable {
    Object injectable = invocation.getInvokedObject();
    Object toInjectInto = invocation.getParameter(0);
    Method[] methods = toInjectInto.getClass().getMethods();
    for(Method method: methods) {
      if (!method.getName().startsWith("set")) {
        continue;
      }
      if (method.getParameterTypes().length != 1) {
        continue;
      }
      Class methodParameterType =
        method.getParameterTypes()[0];
      if (methodParameterType.isAssignableFrom(
            injectable.getClass())) {
        method.invoke(toInjectInto, injectable);
        break;
      }
    }
    return null;
  }
  public static InjectIntoJMockAction injectSelf() {
    return new InjectIntoJMockAction();
  }
}

This code searches for a setter that takes a single argument the type of the mock in question, and if found then invokes it. And this is what the expectation on the mock looks like:

import static yada.yada.InjectIntoJMockAction.injectInto;
...
context.checking(new Expectations() {% raw } {{ 
 allowing(any(Injectable.class)).method("injectInto").with(any(Object.class));
 will(injectSelf());
}}

Seems to work well for me, and a nice example I think of one of the lesser known corners of the power of JMock. The only thing that would be nice is if the:

allowing(any(Injectable.class))

returned a reference of type Injectable. As it is, the use of method(“injectInto”) is a little fragile if I were to refactor the name.

November 20, 2008 jmock java tdd