Testing with Spock

by Lukasz Janicki

What is Spock?

Spock is a unit testing framework that in great extent utilizes Groovy’s syntax making your tests comprehensible and easy on the eyes. Although it is a Groovy technology you can use it to test your Java classes as well. What is the most important is that Spock makes writing tests fun. And I really mean it.

Why Spock?

I have to admit that even knowing all the benefits of TDD and tests over all I considered writing them as little pain in the neck. How has that changed when I started using Spock?

  1. Creating a test in Spock takes less time than using its standard equivalent (combination of JUnit and some mocking framework).
  2. Thanks to the syntactic sugar for mocking, stubbing and spying these operations can be accomplished by really simple code, hence they do not veil test’s logic.
  3. Spock enforces developers to arrange their tests in BDD like form, what makes your test even more clear.
  4. Thanks to Groovy’s syntax you can improve tests clarity even further using closures and straightforward map ulization (see good practices at the end of this post).

Taking all into consideration I gather that tests created in Spock tend to be more informative, better arranged and easier to understand for other developers. Plus they simply look splendidly. What’s the most important is that Spock has turned testing into an extremely pleasant and rewarding experience.

Simple test in Spock

Below you can find a simple test written in Spock.

Of course as the above test is broken (we are putting 1 into list and then expect 2 to be retrieved) test will fail. Spock will display a clear and easy to understand error message, explaining precisely what went wrong.

Test structure

Please take notice how clear a declaration of a test in Spock is. Developers do not have to follow the standard naming convention for methods and instead can declare the name of a test between two apostrophes. Thanks to that creating long but descriptive names for tests seems more natural and as well allows others to better understand what the purpose of a test it.
As mentioned before tests in Spock are arranged in a way resembling BDD tests. Each test can be divided into three sections.

Given section

First of all we want to specify the context within which we would like to test a functionality. This is where you want to specify the parameters of your system/component that affect a functionality that is under the test. This section tends to get really big for all Spock rookies, but ultimately you will learn how to make it more concise and descriptive.

When section

This is where we can specify what we want to test. In other words what interaction with tested object/component we would like to study.

Then section

Now, here we verify what the result of the action performed in when section was. I.e. what was returned by the method (black box test) or what interactions have taken place in mocks and spies used inside tested function (white box test).

Alternative sections

In Spock documentation you will be able to find some alternatives for the above sections, e.g. setup, expect. The latter one is particularly interesting as it allows to create an extremely tiny tests.

Stubbing method calls

In Spock we can distinguish three classes that are able to override a behaviour of some other class or interface: Stubs, Mocks and Spies. In this section we will focus on Stubs as unlike two others imitating other classes is their only responsibility. Nevertheless the syntax for imitating behaviour is the same for all three classes, hence everything shown here will work the same way with Mocks and Spies.

Creating Stub

In order to create a Stub one has to call the Stub() method inside a Spock test.

Specifying the return value

Basically what we want to do with Stubs is to define what should happen when a particular method of stubbed class is invoked. In order to specify what value should be returned by stubbed method we use right shift operator >> and then specify the return value.

Specifying side effects

If we want to specify some side effect as the result of method invocation we put a closure after right shift operator. Thus every time the method be will invoked during the execution of the test the code within the closure will be executed.

Throwing an exception as the result of method invocation

We can use the above side effect technique to throw an exception when a method is invoked.

Specifying different behaviour based on invocation order

We are able to define different behaviour of stubbed method based on the invocation order. In the below example a 1 will be returned as a result of first invocation of method size(), for the second invocation a 2 will be returned and for the third time and further a 3 will be returned.

We can even mix this notation with custom behaviour syntax.

Conditional behaviour of stubbed method

We can specify various behaviours for stubbed method based on some conditions. Let’s say that in this case everytime a method updateRoleAndReturnPreviousOne() is invoked with Role.ADMIN parameter an exception should be thrown. Otherwise Role.USER should be returned as the result. Please note that this time, the method we stub takes a parameter, hence the underscore in method invocation: updateRoleAndReturnPreviousOne(_). Methods taking parameters will be covered in the next section, but for the time being let’s say that this notation can be basically translated into: whenever the updateRoleAndReturnPreviousOne() method is being invoked with one parameter: execute following action (closure after right shift operator) or return following value (value after right shift operator).

Stubbing methods that take parameters

Basic parameter matching

Let’s elaborate a little on the problem that was raised in the previous example. As you could see from the above examples in order to mimic a particular method we need to invoke it in the same way we would normally invoke this method in our code. So what should we do, if we would like to mimic a method that takes parameters? Does the ‘stubbing’ invocation have to pass parameters as well or should we omit their declaration? Let’s find out in the below example what happens if we choose the latter.

As you can see here, Spock was not able to match the invocation that happened inside expect section with the stubbing declaration we defined in the given section. On the other hand if we had specified that every time the get() method is invoked with parameter equal to 0, a 0 zero should be returned, the above example would have worked. This turns out to be quite handy, as we can explicitly specify what should be returned when a method is invoked with a particular parameter.

Matching complex objects passed as parameters

We can take it even further and bind a kind of validation of a parameter into the stubbing declaration. Let’s imagine we have a UserService interface with a method called save() that takes a User object as a parameter. User class has a String attribute called name.

Let’s now specify that when save() method is called from UserService an exception is being thrown. To make it more sophisticated, let’s assume that this exception should be only thrown when the user with name Michael is being saved.

If you run this example you will find out that the stubbed behaviour was executed only for the case when user passed to the save method had indeed name Michael. The only limitation for the expression inside the closure is that it has to evaluate to a boolean value, other than that the sky is the limit.

Arguments matching wildcards

If you do not want to specify the explicit values for parameters in stubbed methods you can use wildcards. Spock provides following wildcards:

Checking interactions on Mock/Spies

Sometimes you do not really need to specify the behaviour of a dummy object you create for your unit test. Rather than that you are interested in checking whether a particular method from some interface has been invoked during the execution of your programme. To achieve that you can use Mock or Spy. In this section we will discuss the former of two, but everything presented here can be used with Spies as well.

Using mocks has one drawback though that we have to be aware of. When we check interactions, rather than verifying a contract of some interface, we are testing its particular implementation. Nevertheless, tests checking interactions on components can be really handy in case we carry out a large refactoring and e.g. we want to make sure that as a result we will not loose a crucial validation before inserting data to database.

Creating Mock

In order to create a Mock one has to call Mock() method inside a Spock test.

Checking interactions with Mock object

Now that we have created a Mock object, we can check what has happened with the object during the execution of code inside when section.

We check interactions in then section. Likewise specifying custom behaviour for Stubs, to verify interactions with a Mock we need to call the method that we want to study. Prior to that we specify a cardinality of interactions that we expect that have happened. Here we assume that a method size() from mocked object has been invoked exactly one time during the execution of the test. Obviously this is not true in our case, thus Spock will inform us about the failure of our assertion.

Matching invocations in mocks

The same means that were used to match invocation for stubbing can be used with mocks.

Specifying a cardinality of an interaction

In the above examples we always checked whether a method has been invoked once, of course Spock allows us to do much more.

Check the order of execution

What is more you can even specify the order by which interactions should take place. This is achieved by creating numerous then sections.

Now let’s see what happens if we switch statements in when section.

As expected Spock will discover that methods have been invoked in wrong order and will fail the test.

Spy in Spock

Unlike Stub or Mock a Spy is not exactly a dummy object. It’s fair to say that a Spy is rather a wrapper to a normal object. When needed it can override a behaviour of a particular method of some interface and like in Mock the interaction with Spy’s methods can be verified. We will discuss Spies in cooperation with UserService interface.

Creating Spy

In order to create a Spy one has to call Spy() method inside a Spock test. As said before a Spy is a wrapper around an object. Having that in mind, image if we create a Spy using an interface and then some other component will try to invoke a method from the Spy. Unless, we define a custom behaviour for this method an error will be returned.

Rather than creating a Spy from interface, let’s create it the way it is meant to, that is using a class. As UserServiceImpl takes a Transaction argument, creating a Spy will have a different form from what we have been used to by Mocks and Stubs.

Verifying interactions in Spy

Like in Mocks you can verify what interactions have taken place with methods from spied class.

Ok, but how is it different from what a Mock would do, you ask. The answer is really simple, as you can see we did not change the behaviour of the save() method. Therefore if you open the console you will see that the message defined in the UserServiceImpl has been be printed there.

Basically, whenever you want to verify that a method of some particular class has been invoked and you cannot use Mock as for some reason you want the original implementation of this method to be executed, use Spy instead of Mock.

Specifying behaviour in Spy

Like in Mocks and Stubs you can also specify what should be done when a particular method is invoked. Bear in mind that unlike two others Spy will override only a method that it has been explicitly told to override, the implementation of other methods will be unaffacted.

In the above example we have made sure that every time the isServiceUp() method is called it will return the true value. Nevertheless, the implementation of the other method has not changed, thus it has printed out a message to the console once invoked. Basically if you need to override an implementation of one or a number of methods in a class that you use in your test but at the same time want to leave the implementation of others method, use Spy in place of Stub.

Managing exceptions in tests

By far, you should have figured out from previous examples how to verify whether a certain type of exception has been thrown during the execution of a test. Along methods thrown() and notThrown() there is also a noExceptionThrown() method. If you wish to verify details of an exception that has been thrown you can assign a result of thrown() method to a variable and then verify the exception itself.

Extras and catches

There are few catches that you need to be aware of when creating tests in Spock.

Assingments created outside test methods

Assignments created at the level of class are evaluated before every test. This is particularly handy when you do not want to create the objectUnderTest in the body of each test. Instead you can do it at the level of class without the worry that the state of object will be shared between invocations of different tests.

If for some reason you would prefer to share the state of objects created at the level class you can annotate this particular variable with @Shared annotation.

Please note that Spock does not guarantee that tests specified in a class will be executed in the order they appear in the file. Hence, the above example could fail if Spock would run test 2 before test 1. To impose the execution of tests in the order in which they appear in class file we need to annotate a class with a @Stepwise annotation.

Verifying interaction of a method while changing its behaviour

Sometimes we want to both check whether a method has been invoked and change its behaviour. The way that feels the most natural here would be to specify the custom behaviour in a given section and verify if the method was actually invoked in a then section.

What happens here is that Spock does not allow overriding a behaviour of a method for the second time. When test is executed Spock will first search the then section for verification statements. As it finds one for the size() method, the expression list.size() >> 10 in the given section will be ignored as method size() has been already processed. In order to solve this problem we have to combine these two statements into one and put the result into a then section as this is the only place where verification statements can be placed.

Overriding previously specified behaviours

The very same rule applies for every case of overriding already specified behaviour of a method in Stub, Mock or Spy – it is not going to work. The following problem hits me every once in a while. I create a common Stub object for my tests at the class level and define there a behaviour of a particular method. By the time I create another test I forget that this particular Stub is already associated with some custom behaviours. When creating another test, at the method level I define a behaviour for the very same method that would fulfill my needs in this test. Then in the following 30 minutes I fail to realize why the stubbed object does not work as expected. No workaround this time, just be aware that this can happen.

That keyword

Spock tries to enhance the way you write tests, providing you with means to make them more descriptive and as easy to read as stories. In line with this pursuit stands the keyword (static function that has be imported) that. It does not change the logic of your test, but gives you the possibility to modify an expect section.

Good practicies: Using descriptive methods inside test

I always strive to make as descriptive test as possible so that others or even future me will be able to understand what a test is about in the twinkling of an eye. To make it possible I try to reduce the size of given section as this one tends to get really big. What is more I aim to remove all the assingments from this section as well and wrap all stubbing declaration into nicely named methods. Let’s imagine we create a system that allows users to buy tickets for different type of shows: like gigs, movies or theater performances. We want to test whether BookingService responsible for booking tickets for a show specified by an user through a webpage will throw an exception if user performed one of forbidden actions. In this case try to cancel his tickets for a gig that takes place in two days time. Let’s say we allow users to cancel tickets for gigs at most three days before the show, otherwise only administrators can do that. Let’s take a look at test that does this job.

The first thing that can be surprising here is that we stub a lot of methods that do not feel to have a lot in common with our test, e.g. user.getId() or order.status(). The explanation for that is that a person who wrote a BookingService did not thought about dividing it into smaller components and now this class is responsible for too many things. The validation that is of our concern takes place within method conductValidation(), nevertheless before code from this method can be even executed, the validation from the preceding method conductPreValidation() has to be satisfied. Thus, we are forced to stub a number of methods not related to the logic of test – I reckon you have encountered this problem for a number of times.

Let’s mark all the lines that have no effect on the result of the test.

As you can see more than half of stubbed method does not affect the result of our tests. We will try to hide the implementation details from the test scenario and at the same time shrink the given section so that it no longer draws the whole attention of reader. To achieve that we will wrap stubbings into nicely named methods.

I hope that you find it much more clear and less overwhelming. The given section is now easier to understand as it is shorter, exposes parameters that affect test result and at the same time hides ones that are necessary for code to run but have no impact on the tested logic. The one thing that causes my concern is the creation of TicketOrder which does not seem to have any impact on the tested logic, as it is needed only as a holder of Show object. We will remove it the next step.

Removing disruptive code

The next thing I would do with my tests is to remove as much noise from the code as possible. Let’s remove all assignments from the given section as they bring no value at all. I will also move the creation of object under test outside the body of test and create the TicketOrder object in the same method as Show object.

Improve method naming

Just to make our test even less scary let’s play a bit with methods’ names. For instance we will use parameters to avoid having long names without spaces as in the above example.

Good practices: Using “and” label

Apart from section labels like given, when, then there is also a label and that can be used to split former labels into groups of related statements. In my current project I often come across classes which responsibility is to filter out invalid inputs.

Of course names of methods are more meaningful than the ones in the example, but I hope you get the general idea. In tests to cover all the possible cases I write a test for the happy case (all conditions are satisfied) and at least one negative test (when isValidTrade() returns false) per condition from the if statement. The happy case test would look like below.

As I do not want to list all the conditions in a test name I try to come up with some business definition that would suggest others what is necessary in the particular scenario for positive validation. Now let’s create a test that should fail due to unsatisfied condition no. 2. Just to make sure that my tests will work even if someone rearrange conditions inside isValidBooking() method, in the test I will prepare the Booking object in the way that it satisfies all conditions, but the 2nd one.

As you can see the method bookingWillBePaidByCash() has changed into bookingWillBePaidByCreditCard(), also the name of test says that this will prevent the booking to be classified for a discount. To take this even a step further let’s separate the given section into two groups.

Now we have explicitly separated the given section into two sections that affect the object under test in opposite ways. Also we added descriptions to labels making it extremely clear which section affects object under test in which way.

Good practices: Using maps for method parameters

Let’s imagine we have a BookingService like the one below and we want to create a test that would check whether exception is throw if there is not enough tickets for a particular screening of a movie.

We end up writing a test like the one below.

This is not really bad, but imagine this functionality requires a lot more of stubbing etc. In that case we would like to extract related stubbing into meaningfully named methods.

This is not that bad as well, as parameters of this method somewhat differs from each other. There are cases though when this method could look like this:

In this case how can someone tell that the second parameter is the name of the screenwriter and the third one of the director. Can you still suspect that the number parameter is a number of tickets to be booked when there are two number parameters? In such cases I like to transform this type of method into more comprehensive form using maps.

Parametrized tests

Spock also supports parametrized tests, in which you define a test structure once and then run the same test for different input values. Since I am going to post a separate article on this topic I will just provide you with some teaser for the time being. You can find more complex parametrized tests here.

Setting up Spock

To start working with Spock you only need to add one additional dependency to your project. You can also play with Spock through the web console online application. One thing to remember though is that every Spock test has to extend class Specification.

External links

Sharing is caring, let others know!

Share this:

return to home