Goodbye JUnit, Hello Spock Framework

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
2
3
4
5
6
7
8
9
10
def 'sample test'() {
given: 'an configured instance of the test class'
def foo = new Foo()
and: 'an input object'
def bar = new Bar()
when:
def result = foo.foobarize(bar)
then:
result == 10
}

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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class FooTest {
private void doFooTest(Integer something, String another, String expectedValue) {
Foo foo = new Foo();
assertEquals(expectedValue, foo.doSomething(something, another));
}

@Test
public void testSomethingAndAnother() {
doFooTest(1, 'bar', 'green');
}

@Test
public void testSomethingOnly() {
doFooTest(1, null, 'hamburger');
}
}

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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class FooTest extends Specification {
@Unroll('#featureName - #testCase')
def 'something or another'() {
given: 'a Foo'
def foo = new Foo()
when: 'something is done'
def result = foo.doSomething(something, another)
then: 'result is expected'
expectedValue = result
where:
testCase | something | another | expectedValue
'something and another' | 1 | 'bar' | 'green'
'something only' | 1 | null | 'hamburger'
}
}

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
2
3
4
5
someMap['carrot'].theFoo == expectedValue
| | | | |
| | 53 | 23
| [theFoo:53] false
[carrot:[theFoo:53]]

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?