Unit Testing with Groovy

This post is about unit testing with Groovy. Groovy was the first language I used after Java. It lets me do a lot of the things I do with Java, but more quickly. Like many developers who are using another language after Java for the first time – whether it be Ruby, Scala, Groovy or something else – I’ve quickly come to love it.

In this post I’m going to show you how Groovy can make your tests more succinct. We’ll focus on syntax sugar for creating and consuming Maps and Lists, which is something you do a lot of when preparing data for a unit test. Than I’ll give a quick introduction to closures, which will lead us into some of the techniques we can use for mocking in Groovy.

So why would you want to consider Groovy?

The first thing you should know about Groovy is that it is very similar to Java.  About 90% of Java code pasted into a Groovy file will work unchanged, and it only takes pretty small changes to make the remaining stuff work.  As a result, it’s not too hard to move a Java team over to Groovy.

The chief benefit you get from using Groovy is a cleaner syntax. Things that take a long time to type out in Java – such as defining lists and maps – are gone, thanks to cleaner syntax.

To change your build to use Groovy is quite easy.  For example in Ant, you add the Groovy jar to the classpath and change the javac task to groovyc instead.  groovyc will build both Java and Groovy and link between them.  There are also similar tools for Maven users.

An important point to remember is that you don’t need to rewrite your old code.  Groovy compiles down to bytecode so Java can call Groovy methods and vice-versa.  You can still use all your existing Java projects and libraries with Groovy, and in some cases you can enhance them too.

Collections

Let’s now look into how Groovy can make it easier for you to set up data in your tests.

Lists

One of the most commonly used shortcuts you’ll use in your tests is the shorthand for Lists. You can create an ArrayList by wrapping the elements in brackets and separating with a comma:

List days = [ "Monday", "Tuesday", "Wednesday" ]

Because Groovy is a dynamic language, you don’t even need to declare the type at the front – you can use the def keyword (notice also that the semicolon at the end is optional):

def days = ["Monday", "Tuesday", "Wednesday” ]

If you’d like to create something other than an ArrayList, you can use the as keyword to cast the type to something else.  So if I want it to be an array of strings instead of a list, I do this:

def days = ["Monday", "Tuesday", "Wednesday” ] as String[]

For accessing elements in the list, instead of get(), you can use square brackets:

println days[1]   // days.get(1)
     Tuesday

But why stop there? You can use negative indexes to return the elements from the end of the collection:

println days[-1]
     Wednesday

You can get also get a sublist by specifying a range:

println days[1..2]
     [Tuesday, Wednesday]

or return a range using the negative indexes of a list:

println days[-1..-2]
     [Wednesday, Tuesday]

Maps

For maps, the syntax is one step up from a list. Each key-value pair is separated by a colon:

def aussieCapitals = [
     Victoria : ‘Melbourne’,
     Queensland: ‘Brisbane’]

To get the element in the list, I use the same syntax for a list, except now the key is a string, not an integer:

aussieCapitals[‘Victoria’]
     ‘Melbourne’

BTW, you may have noticed I’m using single quotes instead of double quotes –  that’s another Groovy shorthand.

So let’s now compare the verbosity of Java:

 Map aussieCapitals = new HashMap();
 aussieCapitals.put("Victoria", "Melbourne");
 aussieCapitals.put("Queensland", "Brisbane");
 aussieCapitals.put("New South Wales", "Sydney");
 aussieCapitals.put("Tasmania", "Hobart");
 aussieCapitals.put("Australian Capital Territory", "Canberra");
 aussieCapitals.put("South Australia", "Adelaide");
 aussieCapitals.put("Northern Territory", "Darwin");
 aussieCapitals.put("Western Australia", "Perth");
 assert ("Perth".equals(aussieCapitals.get("Tasmania")));

with that of the equivalent Groovy:

def aussieCapitals = [Victoria: 'Melbourne', Queensland: 'Brisbane', 'New South Wales': 'Sydney', Tasmania: 'Hobart', 'Australian Capital Territory': 'Canberra', 'South Australia':"Adelaide",  "Northern Territory": "Darwin", "Western Australia": 'Perth']

assert "Hobart"==aussieCapitals['Tasmania']

You can see that it’s a lot easier to read a Groovy test than it is to read Java.

Closures

So let’s now briefly digress into closures. Putting aside the strict computer-science definition, for our purposes closures can be thought of as functions that can be passed around as method arguments and then executed in different contexts. You may have come across them before in Javascript.

Most Java developers would have used anonymous inner classes at some point whilst working with Swing UI, threading, etc. These bear the closest resemblance to closures in Groovy.

Consider the following example of a weekdays list. Groovy has added a method to List called each, which takes a closure (the thing in the curly braces) and performs that function on each of the elements. In our example below, the String is a parameter to the closure function that we’ve defined.  The arrow indicates the beginning of the actual function. In this instance, the closure just calls println to print out each element:

def weekdays = [‘Monday’, ‘Tuesday’, ‘Wednesday’, ‘Thursday’, ‘Friday’]
weekdays.each { String it ->
     println """The day is ${it}""" }
The day is Monday
The day is Tuesday
…

Incidentally, notice in the println that I’m printing out a formatted string using the Groovy string syntax – it’s very similar to the expression language (EL) format if you’ve done any work with JSF or Spring.

If we want to use closures on maps as well, we can. This time, I’m feeding two variables into the closure method:

aussieCapitals.each { key, value ->
     println """The capital of ${key} is
     ${value}""" }

-> The capital of Victoria is Melbourne

This prints out the key-value pair. Notice that the type is optional – it’s like implicitly having the def keyword in there.

The other method I’m going to show you is collect. All this does is iterate through the collection, perform the method on each of the elements, and return the output as a new collection:

aussieCapitals.collect {k, v ->
     return v.toUpperCase() }
[‘MELBOURNE’,’BRISBANE’,…]

Unit Testing Support in Groovy

Groovy includes some excellent new tools for unit testing: a new assertion method, a JUnit 3 test harness called GroovyTestCase, and a mocking framework that provides a mechanism for mocking with closures. We’ll discuss some of them here.

Power Asserts

Groovy comes with an assert statement built into the language that is able to introspect objects and provide a more descriptive output about when an assertion fails.

As you may already know, a regular assert that looks like this:

assert (Arrays.asList("Monday","Tuesday","Wed").contains("Friday"))

will throw you a pretty boring assertion error in Java:

Exception in thread "main" java.lang.AssertionError
at AssertDemo.main(AssertDemo.java:5)

In Groovy the output is considerably better, showing the evaluation of all the statements elements:

Furthermore, unlike assertions in Java, you don’t need to specify the –ea flag to catch a Groovy assert.

MockFor and StubFor

This is Groovy’s built-in mocking framework and it’s a great example of some real ‘groovy’ features put to good use:

void testMockOutTheWeatherClass() {
     def weatherMock = new MockFor(WeatherReport)
     weatherMock.demand.with {
          predictWeather { Weather w-> "Injected Code" }
          yearlyMeanTemp { 17.5 }
     }

     weatherMock.use {
          def report = new WeatherReport()
          def prediction = report.predictWeather()

          assert "Injected Code" == prediction
          assert report.yearlyMeanTemp() == 17.5

          // an automatic 'verify' happens at the end of the closure
     }
}

You can see that we specify the class to mock in the MockFor constructor.

MockFor will add a property, demand, that we then use to dictate what the mock should return, and in what order.  The with closure is a bit of shorthand to save repeating weatherMock.demand over and over again.

In this mock we are saying that the predictWeather method that takes a Weather, will be overwritten by our injected closure, and then yearlyMeanTemp will be called and return 17.5.

The use block runs the actual test and performs the assertions.  The calls to the WeatherReport constructor and the mocked methods are proxied within the use block.  The assertions are called, and in another good demonstration of the power of closures, an implicit verify is called at the end.

The syntax for StubFor is almost exactly the same, except the demands in the use block will return unlimited times.

Implementing a Class Using a Map

This is my favourite Groovy feature.  Its actually part of the Groovy language, but can be used for mocking. In short, Groovy lets you define an implementation of a class as a map of its method names to closures. For example:

def alwaysEqualComparable = [
     compareTo: {Object o -> return 0; }
] as Comparable

assert (alwaysEqualComparable instanceof Comparable)

Given that when you write a mock or stub, you are specifying an alternate implementation of an interface to use, you can use this technique for testing:

@Test void makeYourOwnImplementation() {
     def goodWeatherSvc = [
          getTemperature : {BigDecimal lat, BigDecimal longitude -> return 25.6},
          getConditions : {BigDecimal lat, BigDecimal longitude -> return "Sunny"}
     ] as WeatherService

     TravelAdvisor cut = new TravelAdvisor();
     cut.setWeatherService(goodWeatherSvc);

     assert cut.shouldIGo(35.2, 12.123)

     def badWeatherSvc = [
          getTemperature : {BigDecimal lat, BigDecimal longitude -> return 3.5},
          getConditions : {BigDecimal lat, BigDecimal longitude -> return "Freezing"}
     ] as WeatherService

     cut.setWeatherService(badWeatherSvc)
     assert !cut.shouldIGo(23.21, -144.23)
}

You’ll see that I’ve got a weather service interface that defines two methods, getTemperature and getConditions

I create a map of method names to closures, where the closures are my mock implementations.

Then I say ‘as WeatherService', and the as keyword generates a class instance.  I can then go ahead and inject my service into the class under test.

To do the same again to test a different condition, all I need to do is define another implementation badWeatherSvc.

But there’s more…

I’ve only touched upon some of the great features of Groovy here. Some other useful features worth investigating are the Safe Navigation Operator to reduce null checks, Regular Expression shorthand, and the ability to set properties via dot notation or as constructor args.

Furthermore, like other scripting languages, Groovy makes it possible to add methods at runtime to legacy code.  This is great if you don’t have the source, or you just really think the designers of your favourite API really should have added some useful method that you ended up having to  write a util class for.

The Groovy devs have ‘groovified’ the entire JDK with such extensions.  Here is an example of a new File.readLines() method that reads the file and returns it back as a list of strings without the need to manage a BufferedLineReader or InputStream:

1 List lines = new File(‘testInputList.txt’).readLines();

These enhancements are known as the Groovy JDK and worth investigating to reduce the brevity of your own tests.

Summary

As you can see, Groovy provides some useful syntax to get the more mundane aspects of Java programming and testing out of the way.  Those wanting to dip their toes in a new language can try using Groovy for unit testing as a starting-point,  as the risk to your production code is minimised.  Given the syntax sugar provided, you’ll spend less time writing your unit tests. Furthermore,  the less verbose nature of Groovy also means your tests should be more decipherable and expressive of the feature they are trying to test.

Those wanting to take more advanced features of Groovy can use closures, along with Map-based implementations and the Meta Object Protocol to re-implement objects at runtime, allowing them to be used the way you need.

References

About Kon Soulianidis

I'm a Senior Consultant at Shine Technologies. JVM languages and technologies are my thing. A JVM developer is never short of choice. In my spare time I run MelbJVM, the Melbourne Java and JVM Users group.
This entry was posted in Java, Testing. Bookmark the permalink.

3 Responses to Unit Testing with Groovy

  1. Brad Rippe says:

    Kon nice article!
    One little note, for “Implementing a Class using a Map”. Shouldn’t the assertion be:

    assert (alwaysEqualComparable instanceof Comparable)

    Isn’t alwaysEqualComparable a variable an not class definition? Thanks again for the article!

  2. Kon Soulianidis says:

    Hi Brad,
    Good pickup. This is now fixed.
    Glad you liked the blog.
    Kon

  3. Pingback: The Java Specialists Symposium: Unconference + Retreat = Mad fun | The Shine Technologies Blog

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s