Spock for BDD unit testing in Java

Tanya Maslova
Version 1
Published in
8 min readOct 17, 2022

--

Ok, ok, it is not quite that Mr Spock I will be talking about. But I have to admit I like both. The Spock testing framework for unit tests fits very well with the Given-When-Then unit test pattern. But it seems that not a lot of people know about this framework, and it can’t boast of huge popularity like JUnit.

This little blog gives a brief description of the Spock framework and compares it to the popular dude, the JUnit, to demonstrate what Spock can do. This is not a tutorial on how to use Spock. This is just to give you an idea of what the framework is about and whether you would want to use Spock in your application.

Who, I mean, What is Spock?

As you can tell from the introduction, Spock is a testing framework, not a science officer of the starship USS Enterprise. This framework can be used in unit, component, and integration tests for Java or Groovy applications. For reference and documentation, you can use Spock’s official website https://spockframework.org/.

Spock is written in Groovy. Groovy is a superset of Java, so running our tests with Java applications won’t be a problem. This framework is particularly useful if you have an application that is written in both Java and Groovy because it allows you to write tests for the whole application consistently, structurally, and in one language, instead of having tests partly written in Java and partly in Groovy.

What makes this framework stand out, apart from its obvious resemblance to the famous Star Trek character, is that it enforces Behaviour Driven Development (BDD) and Test Driven Development (TDD) conventions. And it makes the Given-When-Then unit test pattern easy to implement. That really is what Mr Spock would probably do, if he was into unit testing. In case you didn’t know, Given-When-Then is an approach introduced by Chris Matts and Daniel Terhorst-North as part of BDD. This approach is more commonly used in integration testing. But is also used in unit tests to promote TDD, ensure structural approach, readability, and maintainability of unit tests as well as consistency in how our unit tests are written. Spock allows you to identify the behaviour of a class in a readable and easy-to-understand manner before we start developing that class.

Spock framework is supported by different IDEs such as InteliJ and Eclipse and can be easily integrated into Spring or SpringBoot applications. For example, here is how a maven pom.xml would look like:

And here is an example in Gradle:

There are a lot of tutorials out there to get you started with Spock if you are not familiar with it. But the support community is not as wide as for JUnit.

Spock vs JUnit

It is a difficult battle for Spock. And I don’t think there will be a winner. It actually depends on the application and preferences of the team writing this application.

Given-When-Then Unit test pattern

Imagine we are writing an API for a boring and possibly slightly dodgy car-hiring company. The API retrieves all available cars to hire and also gives the estimated cost of cars a customer wants to hire based on the type of car and the period of hire. We decided to have a calculator that would calculate the hiring cost. We want the calculator to return 0 when there are no cars selected. So the unit test scenario will be :

Given: empty list of cars

And: valid hire period

When: calculate hire cost

Then: return 0

Here is a unit test written with JUnit5 that tests this scenario:

Unit test in JUnit5

And here is a unit test written with Spock:

Unit test in Spock

As you can see, with Spock we have a Given When Then block and a scenario description. We don’t need to define these blocks in comments as we did in JUnit. And when we write these specifications and tests before we have developed the calculation method, we do so in a more “human” language. Which makes it clearer what behaviour we want to achieve and what we are testing.

If you are not a fan of writing an essay for a unit test, Spock also allows defining Given When Then without description.

Mocking and Stubbing

There are a lot of mocking frameworks out there that we could use with JUnit. For this comparison, we will use Mockito as JUnit sidekick (or minion).

Spock, on the other hand, has its own built-in mocking stubbing and spying. So it does not require additional libraries to be added. Spock pretends to be very strict about differentiating between stubbing and mocking. And indeed, in testing, when we say “mock”, we mean that we mock the whole class, when we say “stub”, we stub a certain behaviour of that class. So if we stub something in Spock, it is not mocked. However, just like in Mockito, in Spock, it is possible to stub a behaviour in a mocked class and also verify how many interactions we have with that class. The only difference is where we verify the interaction.

Imagine our slightly dodgy car hiring company wanting to surprise their customer with some additional admin fees on top of the hiring costs right at the end of the checkout. Our service will retrieve hiring costs based on user selection, retrieve the admin fees, and return the combined result. And voila, the customer will be charged more!

This is how our JUnit test for this sneaky behaviour might look like:

Unit test in JUnit5

And this is how a unit test will look in Spock:

Unit test in Spock

In Spock, we define how many interactions we expect with the mocked class where we stub the behaviour (in the Given block). In Mockito we verify how many interactions we have in the Then block. In both cases the result will be the same and the meaning the same — we expect only one interaction with the AdminFees. If there are more than one or no interaction both tests will fail.

Testing for Exceptions

Both Spock and JUnit enable us to test whether a certain behaviour throws or does not throw exceptions. Spock uses thrown() to verify whether an exception is thrown and notThrown(), as you can tell, to verify that exception has not been thrown.

Getting back to our API for a slightly dodgy car hiring company, we decide that our hiring cost calculator will complain if provided with the incorrect period for hire. For example, the period provided could be in the past, or the to and from dates are reversed, or even worse, the period is not provided at all. In this case, we want our service to get very cross and throw an exception at the offender.

Our unit test in JUnit will look like this:

Unit test in JUnit5

And in Spock:

Unit test in Spock

Documentation and Readability

As you have seen from previous examples, Spock enables us to document how we expect our class under test to behave in a more human language. Readability allows a better understanding of what sort of behaviour we expect and what we are testing. This in turn provides better maintainability and a better understanding of the system behaviour, code, and test.

When we run our tests we want to see what sort of behaviour has been tested and what has been expected in that behaviour. In JUnit, the clarity depends on the way we name our test method. The behaviour in our example is not very human-readable but we can still understand it (provided it is a developer that looks at the test execution):

JUnit test execution in InteliJ

And this is what we will see upon our Spock test execution:

Spock unit test execution in InteliJ

And once again Mr Spock, I mean Spock framework, makes the execution documentation more readable. Almost like a poem. Even a person with little IT knowledge or programming skills can understand what VehicleCostCalculator should do.

Summary

In this blog, we only looked at Spock in unit tests. Spock enables us to test Java/Groovy applications in the same way we would with JUnit, including mocking dependencies.

Unlike JUnit, Spock does not need any other frameworks for mocking, spying, and stubbing. So we don’t need to add additional libraries. Spock prefers to work alone. Even though Spock is quite strict with mocking and stubbing, we can mock and test interactions with mocks just like Mockito/JUnit team.

One of the main advantages of Spock is that it allows us to write unit tests in a consistent, structural, and more readable way. Readability enables us to understand what we expect from the behaviour of the class under test, and what we are testing. In addition, it enhances the maintainability of our tests, code, and application.

Spock is supported by many IDEs but does not have as big a support community.

In the end, it is up to the development team to consider whether to use Spock or go with something else, such as JUnit.

If you wish to have a look at an API made for an imaginary slightly dodgy and boring car hiring company used here as an example to demonstrate Spock in the unit test, you can get it from git hub repository.

About the Author:
Tanya Maslova is a Java Developer here at Version 1.

--

--