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.
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
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.
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.
No related posts.