Scripting Custom Actions

Using a custom action1 in an expectation is straightforward but requires quite a lot of code. You need to define a class that implements the action and a factory method to make the expectation read clearly. The jMock Scripting Extension lets you define custom actions inline in the expectation, as BeanShell2 scripts.

Because a script is represented as a string, it does not play well with refactoring tools.

First, you need to add the following JARs to your classpath:

Second, you need to import the "perform" factory method into your test.

import static org.jmock.lib.script.ScriptedCallbackAction.perform;

You can then use the "perform" factory method to define custom actions using a BeanShell script. The script can refer to the parameters of the mocked method by the names $0 (the first parameter), $1, $2, etc. For example, the script below calls back to a Runnable passed as the first (and only) parameter:

checking(new Expectations() {{
    oneOf (executor).execute(with(a(Runnable.class))); will(perform("$0.run()"));
}}

A script can pass literal values as parameters to the callback. For example, the script below adds an integer to a collection:

checking(new Expectations() {{
    oneOf (collector).collect(with(a(Collection.class))); will(perform("$0.add(2)"));
}}

If you want a script to refer to an object defined by the test, you will have to define a script variable with a "where" clause. Any number of where clauses can be appended onto the perform clause to define variables. For example, to translate the code from the custom action recipe3 to use a BeanShell script, we must define a script variable for the list of mangoes to be added to the collection:

final FruitTree mangoTree = mock(FruitTree.class);
final Mango mango1 = new Mango();
final Mango mango2 = new Mango();

context.checking(new Expectations() {{
    oneOf (mangoTree).pickFruit(with(a(Collection.class))); will(perform("$0.addAll(mangoes)")
            .where("mangoes", Arrays.asList(mango1, mango2));
}});

...

Links:

1. custom action: http://www.jmock.org/custom-actions.html

2. BeanShell: http://www.beanshell.org/

3. custom action recipe: http://www.jmock.org/custom-actions.html