I don’t write many JUnit tests anymore. I’ve been using JUnit for years, first version 3 and then version 4. Combined with various frameworks such as Spring, EasyMock, and others, it worked reasonably well. But it always seemed so verbose and almost as much work, if not more, as writing the code itself. So I’ve stopped writing them.
That doesn’t mean I don’t write unit tests.
In the last year or so, I was introduced to the Spock Framework. Ever since, writing unit tests hasn’t been the same. I actually write them!
Unit Test Lethargy
Much software isn’t as well tested as it should be. Nearly everyone I talk to has a similar response to the subject of unit testing: “Yeah, we have some unit tests, but not nearly as much as we’d like”. It’s like eating fruits and vegetables. We all know we should eat healthier and cut back on things like soda and donuts, but few of us actually do.
I’ve certainly fallen off the unit testing wagon more times than I care to admit. I get lazy, deadlines loom, and my grand intentions fall by the wayside. Then bugs are found, I wonder why my code is so convoluted, or I read something extolling the benefits of testing. I get back up, dust myself off and get back to writing unit tests.
Spock changed all that.
Since I was introduced to Spock, I’ve been pretty good about keeping up with unit tests. There are many reasons, but the ease of writing tests is a big one.
Here are four reasons why I think Spock has makes it easier and more enjoyable to write tests.
Given When Then
One of the first thing you’ll likely notice about Spock is that it provides a structure for you to build your tests around. In the same way a jazz musician improvises around a structure of chord changes, Spock allows you to compose your tests using the given-when-then structure–given some condition, when the code is executed, then some new conditions exist.
1 | def 'sample test'() { |
This is obviously a simplistic example, but notice how logically it reads. Not only that, each block documents itself in a way that almost reads like normal english!
Data Driven Tests
By far, my favorite feature in the Spock Framework is the ability to build tables of test data to drive a single test. With JUnit, I would spend a fair amount of time refactoring tests into a common, parameterized method, just so I could test different data combinations. My tests might have looked something like this:
1 | public class FooTest { |
With Spock, I can write the test, and then feed in different data values by creating a table of data in the where clause. The same test is run for each row in the table of data. For example:
1 | public class FooTest extends Specification { |
With this feature, I can construct dozens of test permutations very quickly and compactly. I find this much easier to read than the previous JUnit example. The test and the data are all expressed in one place.
If the Spock Framework provided nothing else, this would be worth the switch by itself!
It’s Groovy
If you haven’t noticed yet, the examples so far don’t look exactly like Java. That’s because Spock tests are written in Groovy. While Groovy looks a lot like Java, it has a lot of features that make it easy to express a test scenario very compactly.
- Closures. The ability to pass function looking constructs around. Groovy includes many constructs that look very similar to Java 8’s lambda and Stream support. This is especially nice if you’re not able to use Java 8 features yet.
- Collection casting. Need to convert a string array to a List or a List to a Set? Just cast it with “someArray as List” or “someList as Set”, respectively. 1* Collection comparison. Maps, Lists, Sets and the like can be compared using the ‘==’ operator. I no longer have to rely on utility libraries such as Guava’s Maps.difference method to compare Maps, for example.
- Object initialization. Groovy makes it possible to initialize an object’s private data on construction: new Foo(someField: 5, anotherField: “blue”)
- No semicolons required. This might seem like a minor point, but it cleans up the code a bit. I’m getting better, but I still automatically type those darn things!
There’s a lot more power to Groovy. I’m still learning all the idioms and features, but it definitely makes it easier to express the conditions of a test very quickly and succinctly.
Useful Failure Output
If I have an assertion at the end of my test that looks something like this, and it fails, where is the problem?
1 | someMap['carrot'].theFoo == expectedValue |
The Map, someMap
might be missing the required key, theFoo
might be null
or have the wrong value. Prior to Spock, you’d have to set breakpoints and inspect the various pieces of the expression to determine why the test was failing. With Spock, you get output that looks like this:
1 | someMap['carrot'].theFoo == expectedValue |
From this result, you can immediately see which part of the expression caused the condition to fail. Now you can zero in on what is broken and less time figuring out where things went wrong.
And Much More
These are just the main features I like. Spock and Groovy have many features which all combine to make writing unit tests easier and faster.
Part of my recent success in writing unit tests may have to do with the novelty of learning Spock and Groovy. But I have a feeling that the features provided will keep my writing unit tests, long after the new tech smell has faded.
If you’ve been negligent in writing unit tests as of late, take a look at the Spock Framework. Find something to make it interesting and easy to write the unit tests you know you should. For me, that something is Spock and Groovy.
Try it and see what you think.
Question: What are your impressions of the Spock Framework?