Reading Time: 10 minutes

Automated testing using XUnit style frameworks can be achieved using several techniques. You can test a particular class, group of classes, or all your system at once. This selection will conform your SUT (system under test). You must define which technique or mix of techniques to use depending on your system and what best suits it.

In case you are trying to isolate your SUT form other components, such as collaborators, then you will need to create a “double” of this dependency that can be used instead of the real one. There are several approaches on how to define a “double”: Dummy objects, Fake objects, Stub objects and Mock objects (there’s an interesting article about what a “double” is and what each type of “double” does). Each one enable your code to test different things, so once again, it’s up to you to decide which one to use.

latest report
Learn why we are the Leaders in API management and iPaaS

I won’t discuss about how to create mock objects, there are several APIs to use out there well documented. There’s no much to say about Dummy objects so let just focus on creating Fake and Stub objects. For the creation of such kind of objects we are going to compare Groovy with java.
I think Groovy rules over java and the reason is that groovy syntax allow us to create objects, collections and interface implementations with much less code than java. The main groovy feature that allows this is interfaces implementation with closure or map. Using these feature we can create “double” objects to use as collaborators for the SUT. It usage reduces burden of writing an entire class to provide a “double” implementation for the class under test.

Note: Another very useful feature to reduce code during testing is how groovy creates and manipulates collections and objects.

Implementing interfaces using Groovy:

Suppose we have NotificationSender interface and we want to create a Stub object using groovy so we can use it during testing. So we can create an implementation in groovy using a closure or a map.

Implementation using closure

As we are using closure, we don’t have any way to know which method is being executed, so the closure parameters must be an array of Objects. Depending on the parameters we receive we can chose which logic to execute. In general, closure are better for one method interfaces.

Implementation using a map

Maps are better than closure to implement interfaces with several methods, but we can still only declare the method we want to implement in the map. If a call to a not implemented method is done, then a NullPointerException is thrown.

Using a map to implement an interface also allows you to create several implementations reusing behavior for each method. If you define 2 implementations of sendNotification(), 2 implementations of isEnabled() and another 2 implementations of destinations() method, then you can create several instances of NotificationSender mixing those implementations

Creating different interface implementations reusing methods definitions

Creating input method parameters for methods under test is also much easier with groovy since you can set each object property within the object’s creation call

Creating input method parameters

new Notification(type: Type.ERROR, message: "some message", cause: "exception")

Notification must have an empty parameters constructor (if not this won’t work) and using a key value syntax we can set all Notification properties in one line. It’s arguable that you can do the same in java if you have a constructor that declares each property as a parameter but we don’t always want to have such a constructor or we just can’t because we don’t own that code.

Now, let’s compare a test using groovy, and one using java.

Groovy vs Java

In this case we have a Notification feature to test. We have a Notification class representing a notification message. We also have a NotificationManager which responsibility is to manage notification state (delivered notifications count, undelivered notifications count and those notifications objects that were not delivered). It has a collaborator that is represented by the interface NotificationSender. Implementations of NotificaitonSender are in charge of delivery a notification message. As we don’t want to use a real implementation of NotificationSender we are going to use a Stub object. In this case the SUT is composed by Notification and NotificationManager.
You can download example project from here.

Groovy test

Java test

public class JavaNotificationTest {

    private NotificationManager notificationManager;
    private NotificationSender noFailuresNotificationSender;
    private NotificationSender someFailuresNotificationSender;
    private NotificationSender allFailuresNotificationSender;

    @Before
    public void setUp() {
        noFailuresNotificationSender = new NotificationSender() {
            public boolean isEnabled() {
                return true;
            }

            public void sendNotification(String message) throws NotificationSenderException {
            }

            public String[] destinations() {
                return new String[0];
            }
        };
        someFailuresNotificationSender = new NotificationSender() {
            private int currentMessage;

            public boolean isEnabled() {
                return false;
            }

            public void sendNotification(String message) throws NotificationSenderException {
                if (++currentMessage % 2 == 0) throw new NotificationSenderException();
            }

            public String[] destinations() {
                return new String[0];
            }
        };
        allFailuresNotificationSender = new NotificationSender() {
            public boolean isEnabled() {
                return false;
            }

            public void sendNotification(String message) throws NotificationSenderException {
                throw new NotificationSenderException();
            }

            public String[] destinations() {
                return new String[0];
            }
        };
    }

    @Test
    public void testSuccessfulNotifications() throws NotificationException {/* ... */}

    @Test(expected = NotificationException.class)
    public void testNotificationExceptionIsThrown() throws NotificationException {/* ... */}

    @Test
    public void testSomeFailedNotifications() {/* ... */}

    @Test
    public void testAllFailedNotifications() {/* ... */}

    private List buildNotificationList() {
        return Arrays.asList(buildNotification(Notification.Type.MESSAGE, "exception", "some message"),
                buildNotification(Notification.Type.ERROR, "warning", "some other message"),
                buildNotification(Notification.Type.EVENT, "system update", "another message"));
    }

    private Notification buildNotification(Notification.Type type, String exception, String message) {
        Notification notification = new Notification();
        notification.setType(type);
        notification.setCause(exception);
        notification.setMessage(message);
        return notification;
    }
}

Take a look at the burden of creating a Stub implementation of NotificationSender using Java code. 7 lines using groovy against 40 lines using java. (java code can be shrunken wreaking code style but it takes about 25 lines at least).
Create an object as input parameter for methods under test took 5 lines in java code against 1 line in groovy code.
Overall testing using Java needed 112 lines of code against 71 lines of code using Groovy. And this was a very simple test case. Consider what would happened if we need to create an Stub or Fake object for a much bigger interface, what would happen with the test if we only require to implement a couple of those methods, and what would happen if we need to create several Stubs or Fake objects.

Unfortunately life is not all Charleston and cocktails. Unit testing execution should be done very often, an must be part of project lifecycle, so we want it to be as fast as possible (if not, developers will try to avoid them). Groovy performance is not so great. It takes much more time to execute a groovy test case that a java test case (in this case more than 10 times). So you should consider this before moving to groovy for testing.