The one hour challenge

So I haven't blogged in a long time due to becoming a father. I've gone from having all the time in the world before this and not realising, to having no time and realising it.

I'm going to start a mini series of blog posts where I take an hour to explore something interesting. Think of it as an expanded version of TIL (Today I learned, check my repo here).

What's something useful I've learnt recently?

I've learned to use Groovy and specifically Spock to have short,readable and flexible tests.

Background

Ok, let's provide some background,we only have an hour for this and the code!

As someone who has worked mainly in Java I've looked longily at dynamic languages and how succinct and clever they can be. I even switched from Java to Ruby for a year at a company and enjoyed the experience. Yet even though I enjoyed Ruby I found it hard to utilise on large projects.

Since then I've kept Ruby and dynamic languages in my toolbox for scripts and fun side projects. That was until I was introduced to Spock.

Spock

So let's get to know Spock; a testing framework for both Java and Groovy that lets you write succinct, expressive tests. Think of it as a dynamic version of JUnit and Mockito mashed together.

So why is Spock so good?

  • It's very succinct (yup being paid per usage of that word)
  • It allows both testing and mocking, all your testing needs are in one dependency
  • Tests are easy to read and reason about
  • Oh mah gawd it has data tables

Data tables? That sounds non riveting.

Sheesh, no it ain't. It's like a super powerful testing tool for good (trademarked slogan). How often do you end up writing tests like shouldNotAcceptEvent_WithSpamScoreOf10. Then you handle the second state, so we add shouldNotAcceptEvent_WithNoSpamScore. We keep adding tests for the states we need to handle, we end up with lots of tests. It's pretty common, I've done it a lot, here is where Spock can shine.

With tests, evil can not be spread

Let's take a simple Java class, some play logic to demonstrate Spock. We have a single method isValid and there are multiple combinations of states that we need to test

Our usual way of testing these classes would result in lots of tests, take for example our first pass with Spock. As you can the tests are nice and lean and clear even to non engineers about what they should be doing.

Spock has the concept of data tables, we supply a where block/table of state that allows us to inject multiple variations of state into the same test.

Here's the second past of our Spock tests using the data table feature. Thing to take note of:

  • we define a where table
  • tables must have two columns or more and they are fully fledged variables which can be referenced in the test
  • The variables can be referenced within the test name, adding the annotation @Unroll will mean each iteration will have a new name dynamically generated. Placing # before a variable name in the title of the test will have it inserted upon running the test in question.
Final thoughts on Spock and data tables?
  • Mixing negative and positive assertions doesn't seem the best approach, split into separate tests as we did above.
  • I find Spock tests easier to scan and reason about than JUnit.
  • Not everything needs a data table, remember with great power comes great responsibility, use it for the right use cases not because it's cool.
  • As the test names are dynamically generated you cannot click on a failed test in IntelliJ and go to the failed test in question, this is pretty frustrating.

If you like the idea of data tables then I'd recommend you take Spock for a test drive, with string interpolation and powerful mocking it is a great compliment to almost any project,. I'll be using it moving forwards when and where possible. The small repo with the Spock tests can is here.

Thanks to my lovely colleagues Bob and Jarek who both sang the praises of Spock to my deaf ears for quite some time.

As always I'd love to hear what you think about this article so feel free to either leave a comment below or reach out to me on twitter.