Kinbiko

Groovy: Closures

May 15, 2015

Some technical knowledge assumed.

Often when I work with Java I find myself thinking “This would be so much easier in Groovy…”, and much of the power of Groovy comes from closures. If you’re unfamiliar with what a closure is, for now, think of it as the following(although it is so much more):

A closure is a callable block of code, that you can assign a variable to.

Example:

Closure myClosure = {
    print "love"
}

Let’s have a quick look at something you can do with this new found power: Suppose you have a method:

void myMethod(Closure closure) {
    print "I "
    closure()
    println " Groovy!"
}

Hopefully you’re starting to get the picture. When running myMethod(myClosure) it will print: I love Groovy!

Let’s bring it up a notch. This functionality is especially handy when doing unit testing! Suppose we have the following class:

public class MyClass {
    private Map<String, Thing> things = new HashMap<>();
    private Stuff stuff = new Stuff();

    public Thing doStuffAndGetThings(){
        initThings();
        String name = stuff.doIt();
        return things.get(name);
    }

    private void initThings(){
        if(things.isEmpty()){
            things.put("Thing 1", new Thing(1));
            things.put("Thing 2", new Thing(2));
            things.put("Thing 3", new Thing(3));
        }
    }
    // ...Other methods also calling initThings()
}

In the case where initThings() is called from multiple methods, setting up mock behaviour and mock verifications can be a pain. Here, you could create verifyInitThings and setUpInitThings methods to do these assertions for you. Closures can help you remove the need for multiple methods however, by using the trick we used above.

class MyClassTest {
    @Mock
    private Map<String, Thing> things;
    @Mock
    private Stuff stuff;
    @InjectMocks
    private MyClass myClass;

    @Before
    void init(){
        myClass = new MyClass();
        MockitoAnnotations.initMocks(this);
    }

    void initThingsClosure(Closure closure) {
        //Mock actions
        when(things.isEmpty()).thenReturn(true)

        //Custom checks.
        closure()

        //Mock verifications
        verify(things, Mockito.times(3)).put((String) Mockito.any(), (Thing) Mockito.any())
    }

    @Test
    void testGetThing(){
        def name = 'RG'

        //Create a closure defining the non-initThings() related checks:
        def closure = {
            //Mock actions
            when(stuff.doIt()).thenReturn(name)

            //Call the method
            myClass.doStuffAndGetThings()

            //Mock verifications
            verify(stuff).doIt()
            verify(things).get(name)
        }

        initThingsClosure(closure)
    }

}

This behaviour injection trick has really only scratched the surface of what you can do with closures(did I mention that they can take parameters, and return a value, just like methods can?), but I hope this has whet your appetite, and you’re hungry for more Groovy goodness!


Roger Guldbrandsen

Written by Roger Guldbrandsen.