I’ve always loved tests, ever since the beginning of my programming experience, about fifteen years ago.
I find them invaluable in terms of correctness of algorithms and business requirements, and also in terms of design : if you’re struggling with how to test your code, if you have more lines of code to launch your tests than you have production code, it indicates there’s probably a problem with your code or your tests.
But testing is hard, as much as hard as producing good production code. It’s hard in the sense of it must be readable, way more readable than production code.
As Uncle Bob states in his Clean code book :
“What makes a clean test ? Three things. Readability, readability, readability. Readability is perhaps even more important in unit tests than it is in production code. What makes tests readable ? The same thing that makes all code readable: clarity, simplicity, and density of expression. In a test you want to say a lot with as few expressions as possible”.
And there it hurts. Java is not a model when it comes to concision and expressiveness of code. Making tests in Java takes time, and real test code is buried into ceremony. Sure there are libraries aiming at better readability for test code, but since they’re coded in Java and must respect Java’s syntax rules, they inherit its lack of expressiveness and concision, hence they’re not the panacea.
Let me express myself more clearly here : there’s no panacea, there’s no silver bullet. There’s always a catch.
So what I’ll do in this post is to try to convince you that coding your tests with Groovy instead of Java will help you create more readable - in the broadest sense possible - tests faster.
This article will soon be followed by more in-depth articles detailing real-world examples and solution for unit and integration-testing using Groovy.
You’ll find the code of these examples in its Github repository
The Groovy Language
Of course, before you can write your tests in Groovy you have to learn Groovy.
What ? Learn a totally new language just for my tests ? How can you be productive and write tests faster if you have to lean a new language ?
The answer is simple : the learning curve is not steep. At all. You can learn in less than a day. Actually, if you write Java code, it is valid Groovy code.
This implies that you can start with nearly no Groovy knowledge and progressively make your code groovier.
Of course it also means that, at least for a short amount of time, you won’t be able to use frameworks like Spock, which take full advantage of Groovy’s syntax. Don’t let that discourage you, I’ve discovered Spock only a few weeks ago : I used to do my tests with Groovy (and its built-in JUnit support) only.
So you still can take advantage of more concise and expressive code even if you don’t know how to use specific frameworks.
I won’t discuss here the basics of Groovy syntax, there are many resources available on the Internet. There are also plenty of excellent books, a few of them emphasizing on Java and Groovy integration (e.g. Making Java Groovy). What I’ll do is to show you snippets of code in Java and Groovy that tests the same thing, but unlike many of the tutorials found on the Internet, I’ll show some simple test cases. More advanced ones will be the subject of later articles. As this is the topic of this post, I’ll put the emphasis on code readability
Look ma, no setters !
Let’s look at a simple example : a
Person class, a simple Javabean. It has a few fields : firstname, lastname, birth date, email and a set of addresses.
A word about design here : I know I should hide the implementation of the addresses field, nobody should know it’s a
java.util.Set. But please bear with me on this one ;).
First we test the
equals() method in Java
I find it rather bloated. All this ceremony just to call setXXX on the objects, you don’t need it, you just want to know what the data are.
Look at the Groovy version now :
Tell me, which one is easier to read ? Of course, you could tell me that it’s a matter of taste, but I really find the Groovy one more appealing to the eye.
What about builders ?
Sure you could argue that a builder would be a nicer way to set all data, and I would definitely agree. Actually that’s what I did for some time.
But the problem is that you still have to write your builder, and it takes time. Moreover it has to be done each time again.
It’s unlikely that developers want to create builders just for tests. They want to write less code, not more !
JUnit has suffered for a long time for a lack of parameterized tests. You couldn’t pass parameters to your tests methods. (Well, actually you still can’t pass parameters to your test methods but that’s not the point here.). It has a workaround though : you can create a data provider method, annotated with
@Parameters. You also have to create instance fields which will map to the parameters you want to pass. So instead of passing them directly to your test method, you will set them into the test object instance and refer to them in your test method. It has been borrowed from TestNG.
Given this simple - simplistic ? - example
Let’s look at a parameterized test :
As stated here above, there is a lot of boilerplate in here : the instance fields, the constructor and the data provider method
data() which return a multidimensional array. Once again the real test seems to be buried in the code, thus not easy to read at all.
For the Groovy counterpart, I’ll cheat a bit. Indeed, I’ll use the Spock famework, which is based on JUnit.
No boilerplate code, no clutter, straight to the point. It is nearly self-explanatory. The only thing that needs to be explained is, in my opinion, the
@Unroll annotation. The documentation states :
“A method annotated with @Unroll will have its iterations reported independently.[…] Note that unrolling has no effect on how the method gets executed; it is only an alternation in reporting. […] This method name uses placeholders, denoted by a leading hash sign (#), to refer to data variables a, b, and c. In the output, the placeholders will be replaced with concrete values”
I hope you’ve been charmed by the conciseness and expressiveness of tests in Groovy : less keystrokes, more readability. For me there’s no turning back possible, I can’t use Java for tests anymore, except maybe very very simple ones, but as you can see in the adder example, even for a tiny test like this it’s still painful to do.
This closes this introduction, more articles about testing - with integration with DbUnit, Spring, … - will be available very soon.
If you have some remarks, improvements and comments, feel free to share them.