Spocklight Notebook

Spocklight Notebook
Spocklight Notebook
Buy on Leanpub

About Me

I am born in 1973 and live in Tilburg, the Netherlands, with my beautiful wife and three gorgeous children. I am also known as mrhaki, which is simply the initials of his name prepended by mr. The following Groovy snippets shows how the alias comes together:

['Hubert', 'Alexander', 'Klein', 'Ikkink'].inject('mr') { alias, name ->
    alias = name[0].toLowerCase()
}

(How cool is Groovy that we can express this in a simple code sample ;-) )

I studied Information Systems and Management at the Tilburg University. After finishing my studies I started to work at a company which specialized in knowledge-based software. There I started writing my first Java software (yes, an applet!) in 1996. Over the years my focus switched from applets, to servlets, to Java Enterprise Edition applications, to Spring-based software.

In 2008 I wanted to have fun again when writing software. The larger projects I was working on were more about writing configuration XML files, tuning performance and less about real development. So I started to look around and noticed Groovy as a good language to learn about. I could still use existing Java code, libraries, and my Groovy classes in Java. The learning curve isn’t steep and to support my learning phase I wrote down interesting Groovy facts in my blog with the title Groovy Goodness. I post small articles with a lot of code samples to understand how to use Groovy. Since November 2011 I am also a DZone Most Valuable Blogger (MVB); DZone also posts my blog items on their site.

I have spoken at the Gr8Conf Europe and US editions about Groovy, Gradle, Grails and Asciidoctor topics. Other conferences where I talked are Greach in Madrid, Spain, JavaLand in Germany and JFall in The Netherlands.

I work for a company called JDriven in the Netherlands. JDriven focuses on technologies that simplify and improve development of enterprise applications. Employees of JDriven have years of experience with Java and related technologies and are all eager to learn about new technologies. I work on projects using Grails and Java combined with Groovy and Gradle.

Introduction

The Spock framework is a testing and specification framework for JVM languages, like Java and Groovy. When I started to learn about Spock I wrote done little code snippets with features of Spock I found interesting. To access my notes from different locations I wrote the snippets with a short explanation in a blog: Messages from mrhaki. I labeled the post as Spocklight, because I thought this is good stuff that needs to be in the spotlight.

A while ago I bundled all my Groovy and Grails Goodness blog posts in a book published at Leanpub. Leanpub is very easy to use and I could use Markdown to write the content, which I really liked as a developer. So it felt natural to also bundle the Spocklight blog posts at Leanpub.

The book is intended to browse through the subjects. You should be able to just open the book at a random page and learn more about Spock. Maybe pick it up once in a while and learn a bit more about known and lesser known features of Spock.

I hope you will enjoy reading the book and it will help you with learning about the Spock framework, so you can apply all the goodness in your projects.

Introduction to Spock Testing

In this blog entry we will start with a simple Spock specification for a Groovy class we create. We can learn why to use Spock on the Spock website. In this article we show with code how our tests will work with Spock. To get started with this sample we need Gradle installed on our machine and nothing else. The current release of Gradle at the time of writing this entry is 0.9-preview-3.

First we need to create a new directory for our little project and then we create a new build.gradle file:

$ mkdir spock-intro
$ cd spock-intro
$ mkdir -p src/main/groovy/com/mrhaki/blog src/test/groovy/com/mrhaki/blog

Now we create the build.gradle file:

// File: build.gradle
apply plugin: 'groovy'

repositories {
    mavenCentral()
}

dependencies {
    groovy 'org.codehaus.groovy:groovy:1.7.3'
    testCompile 'org.spockframework:spock-core:0.4-groovy-1.7'
}

Next we create our tests, but in Spock they are called specifications. We only need to extend the spock.lang.Specification and we get all the Spock magic in our hands. We start simple by defining a specification where we want to count the number of users in a UserService class. We are going to create the UserService class later, we start first with our specification:

package com.mrhaki.blog

import spock.lang.Specification

class UserServiceSpecification extends Specification {

    def "Return total number of users"() {
        setup: 'Create UserService instance with 2 users'
        UserService userService = new UserService(users: ['mrhaki', 'hubert'])

        expect: 'Invoke count() method'
        2 == userService.count()
    }

}

Notice at line 6 how we can use very descriptive method names by using String literals. Next we create an instance of the UserService class and pass a list of two users at line 8. And then we check if the return value is the expected value 2 with a simple assertion statement. Spock provides a very readable way to write code. Mostly we first setup code for testing, run the code and finally test the results. This logic is supported nicely by Spock by using the labels setup and expect. Later on we see more of these labels.

Before we run the test we create our UserService class:

package com.mrhaki.blog

class UserService {

    Collection<String> users

    int count() {
        users ? users.size() : 0
    }

}

We can run our code and test with the following command:

$ gradle test
:compileJava UP-TO-DATE
:compileGroovy
:processResources UP-TO-DATE
:classes
:compileTestJava
:compileTestGroovy
:processTestResources UP-TO-DATE
:testClasses
:test

BUILD SUCCESSFUL

Total time: 12.475 secs

The source files are compiled and our specification is run. We get the BUILD SUCCESSFUL message indicating our test runs fine. If the test would fail we can open build/reports/tests/index.html or build/test-results/TEST-com.mrhaki.blog.UserServiceSpecification.xml to see the failure.

We specified the count() method must return the number of users, but we only check it for 2 elements, but what if we want to test to see if 0 and 1 user also return the correct count value? We can create new methods in our specification class, but Spock makes it so easy to do this elegantly:

package com.mrhaki.blog

import spock.lang.Specification

class UserServiceSpecification extends Specification {

    def "Return total number of users"() {
        setup: 'Create UserService instance with users'
        UserService userService = new UserService(users: userList)

        expect: 'Invoke count() method'
        expectedCount == userService.count()

        where:
        expectedCount   | userList
        0               | null
        0               | []
        1               | ['mrhaki']
        2               | ['mrhaki', 'hubert']
    }

}

So what happens here? We use a new label where which contains a data table. Each row of the data table represent a new test run with the data from the row. In the setup block we used an unbound variable userList and in the expect block the unbound variable expectedCount. The variables get their values from the data table rows in the where block. So the first run the UserService instances gets null assigned to the users property and we expect the value 0 to be returned by the count() method. In the second run we pass an empty list and expect also 0 from the count() method. We have four rows, so our test is run four times when we invoke $ gradle test.

We can make the fact that four tests are run explicit by using the @Unroll annotation. We can use a String as argument describing the specific variable values used in a run. If we use the # followed by the unbound variable name will it be replaced when we run the code:

package com.mrhaki.blog

import spock.lang.Specification
import spock.lang.Unroll

class UserServiceSpecification extends Specification {

    @Unroll("Expect to count #expectedCount users for following list #userList")
    def "Return total number of users"() {
        setup: 'Create UserService instance with users'
        UserService userService = new UserService(users: userList)

        expect: 'Invoke count() method'
        expectedCount == userService.count()

        where:
        expectedCount   | userList
        0               | null
        0               | []
        1               | ['mrhaki']
        2               | ['mrhaki', 'hubert']
    }

}

The generated XML with the test result contains the four runs with their specific names:

<?xml version="1.0" encoding="UTF-8"?>
<testsuite errors="0" failures="0" hostname="ci-test" name="com.mrhaki.blog.UserServiceSpecificat\
ion" tests="4" time="0.707" timestamp="2010-06-29T18:17:24">
  <properties />
  <testcase classname="com.mrhaki.blog.UserServiceSpecification" name="Expect to count 0 users fo\
r following list null" time="0.152" />
  <testcase classname="com.mrhaki.blog.UserServiceSpecification" name="Expect to count 0 users fo\
r following list []" time="0.027" />
  <testcase classname="com.mrhaki.blog.UserServiceSpecification" name="Expect to count 1 users fo\
r following list [mrhaki]" time="0.0050" />
  <testcase classname="com.mrhaki.blog.UserServiceSpecification" name="Expect to count 2 users fo\
r following list [mrhaki, hubert]" time="0.0010" />
  <system-out><![CDATA[]]></system-out>
  <system-err><![CDATA[]]></system-err>
</testsuite>

This concludes the introduction to Spock testing. In the future we learn more about Spock and the great features it provide to make writing tests easy and fun.

Original blog post written on June 29, 2010.

Assert Magic

One of the many great features of Spock is the way assertion failures are shown. The power assert from Groovy is based on Spock’s assertion feature, but Spock takes it to a next level. Let’s create a simple specification for a course service, which is able to create new courses:

// File: CourseServiceSpec.groovy
package com.mrhaki.blog

@Grab('org.spockframework:spock-core:0.4-groovy-1.7')
import spock.lang.Specification

class CourseServiceSpec extends Specification {

    def "Create new course with teacher and description"() {
        setup:
        def courseService = new CourseService()

        when:
        def course = courseService.create('mrhaki', 'Groovy Goodness')

        then:
        'Mrhaki' == course.teacher.name
        'Groovy Goodness' == course.description
        !course.students
    }

}

class CourseService {
    Course create(String teacherName, String description) {
        new Course(teacher: new Person(name: teacherName), description: description)
    }
}

class Course {
    Person teacher
    String description
    List<Person> students
}

class Person {
    String name
}

At lines 16, 17, 18 we define the assertions for our specification. First of all we notice we don’t add the keyword assert for each assertion. Because we are in the then block we can omit the assert keyword. Notice at line 18 we can test for null values by using the Groovy truth. We also notice we only have to write a simple assertion. Spock doesn’t need a bunch of assertEquals() methods like JUnit to test the result.

Now it is time to run our specification as JUnit test and see the result:

$ groovy CourseServiceSpec.groovy
JUnit 4 Runner, Tests: 1, Failures: 1, Time: 232
Test Failure: Create new course with teacher and description(com.mrhaki.blog.CourseServiceSpec)
Condition not satisfied:

'Mrhaki' == course.teacher.name
         |  |      |       |
         |  |      |       mrhaki
         |  |      com.mrhaki.blog.Person@34b6a6d6
         |  com.mrhaki.blog.Course@438346a3
         false
         1 difference (83% similarity)
         (M)rhaki
         (m)rhaki

    at com.mrhaki.blog.CourseServiceSpec.Create new course with teacher and description(CourseSer\
viceSpec.groovy:16)

Wow that is a very useful message for what is going wrong! We can see our condition 'Mrhaki' == course.teacher.name is not satisfied, but we even get to see which part of the String value is not correct. In this case the first character should be lowercase instead of uppercase, but the message clearly shows the rest of the String value is correct. As a matter of fact we even know 83% of the String values is similar.

Another nice feature of Spock is that only the line which is important is shown in the abbreviated stacktrace. So we don’t have to scroll through a big stacktrace with framework classes to find out where in our class the exception occurs. We immediately see that at line 16 in our specification the condition is not satisfied.

In our sample we have three assertions to be checked in the then. If we get a lot of assertions in the then block we can refactor our specification and put the assertions in a new method. This method must have void return type and we must add the assert keyword again. After these changes the assertions work just like when we put them in the then block:

package com.mrhaki.blog

@Grab('org.spockframework:spock-core:0.4-groovy-1.7')
import spock.lang.Specification

class CourseServiceSpec extends Specification {

    def "Create new course with teacher and description"() {
        setup:
        def courseService = new CourseService()

        when:
        def course = courseService.create('mrhaki', 'Groovy Goodness')

        then:
        assertCourse course
    }

    private void assertCourse(course) {
        assert 'mrhaki' == course.teacher.name
        assert 'Grails Goodness' == course.description
        assert !course.students
    }

}

class CourseService {
    Course create(String teacherName, String description) {
        new Course(teacher: new Person(name: teacherName), description: description)
    }
}

class Course {
    Person teacher
    String description
    List<Person> students
}

class Person {
    String name
}

When can run our specification and get the following output:

$ groovy CourseServiceSpec.groovy
JUnit 4 Runner, Tests: 1, Failures: 1, Time: 228
Test Failure: Create new course with teacher and description(com.mrhaki.blog.CourseServiceSpec)
Condition not satisfied:

'Grails Goodness' == course.description
                  |  |      |
                  |  |      Groovy Goodness
                  |  com.mrhaki.blog.Course@3435ec9
                  false
                  4 differences (73% similarity)
                  Gr(ails) Goodness
                  Gr(oovy) Goodness

    at com.mrhaki.blog.CourseServiceSpec.assertCourse(CourseServiceSpec.groovy:21)
    at com.mrhaki.blog.CourseServiceSpec.Create new course with teacher and description(CourseSer\
viceSpec.groovy:16)

Spock provides very useful assertion messages when the condition is not satisfied. We see immediately what wasn’t correct, because of the message and the fact the stacktrace only shows the line where the code is wrong.

Original blog post written on July 05, 2010.

Grouping Assertions

In a Spock specification we write our assertion in the then: or expect: blocks. If we need to write multiple assertions for an object we can group those with the with method. We specify the object we want write assertions for as argument followed by a closure with the real assertions. We don’t need to use the assert keyword inside the closure, just as we don’t have to use the assert keyword in an expect: or then: block.

In the following example specification we have a very simple implementation for finding an User object. We want to check that the properties username and name have the correct value.

@Grab("org.spockframework:spock-core:1.0-groovy-2.4")
import spock.lang.Specification
import spock.lang.Subject

class UserServiceSpec extends Specification {

    @Subject
    private UserService userService = new DefaultUserService()

    def "check user properties"() {
        when:
        final User user = userService.findUser("mrhaki")

        then:
        // Assert each property.
        user.username == "mrhaki"
        user.name == "Hubert A. Klein Ikkink"
    }

    def "check user properties using with()"() {
        when:
        final User user = userService.findUser("mrhaki")

        then:
        // Assert using with().
        with(user) {
            username == "mrhaki"
            name == "Hubert A. Klein Ikkink"
        }
    }

    def "check expected user properties using with()"() {
        expect:
        with(userService.findUser("mrhaki")) {
            username == "mrhaki"
            name == "Hubert A. Klein Ikkink"
        }
    }


}

interface UserService {
    User findUser(final String username)
}

class DefaultUserService implements UserService {
    User findUser(final String username) {
        new User(username: "mrhaki", name: "Hubert A. Klein Ikkink")
    }
}

class User {
    String username
    String name
}

Written with Spock 1.0.

Original blog post written on January 29, 2016.

Check for Exceptions with Spock

With Spock we can easily write feature methods in our specification to test if an exception is thrown by the methods invoked in a when block. Spock support exception conditions with the thrown() and notThrown() methods. We can even get a reference to the expected exception and check for example the message.

The following piece of code contains the specification to check for exceptions that can be thrown by a cook() method of the RecipeService class. And we check that exception are not thrown. The syntax is clear and concise, what we expect from Spock.

package com.mrhaki.blog

@Grab('org.spockframework:spock-core:0.5-groovy-1.7')
import spock.lang.Specification

class RecipeServiceSpec extends Specification {
    def "If cooking for more minutes than maximum allowed by recipe throw BurnedException"() {
        setup:
            def recipeService = new RecipeService()
            def recipe = new Recipe(time: 5, device: 'oven')

        when:
            recipeService.cook(recipe, 10, 'oven')

        then:
            thrown BurnedException
    }

    def "If cooking on wrong device throw InvalidDeviceException"() {
        setup:
            def recipeService = new RecipeService()
            def recipe = new Recipe(device: 'oven', time: 10)

        when:
            recipeService.cook(recipe, 2, 'microwave')

        then:
            InvalidDeviceException ex = thrown()
            // Alternative syntax: def ex = thrown(InvalidDeviceException)
            ex.message == 'Please use oven for this recipe.'
    }

    def """If the recipe is cooked on the right device and
           for the correct amount of minutes,
           then no exception is thrown"""() {
        setup:
            def recipeService = new RecipeService()
            def recipe = new Recipe(device: 'oven', time: 30)

        when:
            recipeService.cook(recipe, 30, 'oven')

        then:
            notThrown BurnedException
            notThrown InvalidDeviceException
    }
}

class RecipeService {
    def cook(Recipe recipe, int minutes, String device) {
        if (minutes > recipe.time) {
            throw new BurnedException()
        }
        if (device != recipe.device) {
            throw new InvalidDeviceException("Please use $recipe.device for this recipe.")
        }
    }
}

class Recipe {
    int time
    String device
}

class BurnedException extends RuntimeException {
    BurnedException(String message) {
        super(message)
    }
}

class InvalidDeviceException extends RuntimeException {
    InvalidDeviceException(String message) {
        super(message)
    }
}

Original blog post written on January 21, 2011.

Using the Old Method

Spock has some great features to write specifications or tests that are short and compact. One of them is the old() method. The old() method can only be used in a then: block. With this method we get the value a statement had before the when: block is executed.

Let’s see this with a simple example. In the following specification we create a StringBuilder with an initial value. In the then: block we use the same initial value for the assertion:

package com.mrhaki.spock 

class SampleSpec extends spock.lang.Specification {

    def "after addition of a new value the content is the initial value with the appended value"(\
) {
        given:
        final StringBuilder builder = new StringBuilder('Spock ')

        when:
        builder << appendValue

        then:
        builder.toString() == 'Spock ' + appendValue

        where:
        appendValue << ['rocks!', 'is fun.', 'amazes.']
    }

}

If we want to change the initial value when we create the StringBuilder we must also change the assertion. We can refactor the feature method and show our intention of the specification better. We add the variable oldToString right after we have created the StringBuilder. We use this in the assertion.

package com.mrhaki.spock 

class SampleSpec extends spock.lang.Specification {

    def "after addition of a new value the content is the initial value with the appended value"(\
) {
        given:
        final StringBuilder builder = new StringBuilder('Spock ')
        final String oldToString = builder.toString()

        when:
        builder << appendValue

        then:
        builder.toString() == oldToString + appendValue

        where:
        appendValue << ['rocks!', 'is fun.', 'amazes.']
    }

}

But with Spock we can do one better. Instead of creating an extra variable we can use the old() method. In the assertion we replace the variable reference oldToString with old(builder.toString()). This actually means we want the value for builder.toString() BEFORE the when: block is executed. The assertion also is now very clear and readable and the intentions of the specification are very clear.

package com.mrhaki.spock 

class SampleSpec extends spock.lang.Specification {

    def "after addition of a new value the content is the initial value with the appended value"(\
) {
        given:
        final StringBuilder builder = new StringBuilder('Spock ')

        when:
        builder << appendValue

        then:
        builder.toString() == old(builder.toString()) + appendValue

        where:
        appendValue << ['rocks!', 'is fun.', 'amazes.']
    }

}

Let’s change the specification a bit so we get some failures. Instead of adding the appendValue data variable unchanged to the StringBuilder we want to add a capitalized value.

package com.mrhaki.spock 

class SampleSpec extends spock.lang.Specification {

    def "after addition of a new value the content is the initial value with the appended value"(\
) {
        given:
        final StringBuilder builder = new StringBuilder('Spock ')

        when:
        builder << appendValue.capitalize()

        then:
        builder.toString() == old(builder.toString()) + appendValue

        where:
        appendValue << ['rocks!', 'is fun.', 'amazes.']
    }

}

If we run the specification we get assertion failures. In the following output we see such a failure and notice the value for the old() is shown correctly:

Condition not satisfied:

builder.toString() == old(builder.toString()) + appendValue
|       |          |  |                       | |
|       |          |  Spock                   | rocks!
|       |          |                          Spock rocks!
|       |          false
|       |          1 difference (91% similarity)
|       |          Spock (R)ocks!
|       |          Spock (r)ocks!
|       Spock Rocks!
Spock Rocks!

Note: If we use the old() method we might get an InternalSpockError exception when assertions fail. The error looks something like: org.spockframework.util.InternalSpockError: Missing value for expression "...". Re-ordering the assertion can help solve this. For example putting the old() method statement last. In Spock 1.0-SNAPSHOT this error doesn’t occur.

For more information we can read Rob Fletcher’s blog post about the old() method.

Code written with Spock 0.7-groovy-2.0.

Original blog post written on August 22, 2013.

Mocks And Stubs Returning Sequence of Values

Creating and working with mocks and stubs in Spock is easy. If we want to interact with our mocks and stubs we have several options to return values. One of the options is the triple right shift operator >>>. With this operator we can define different return values for multiple invocations of the stubbed or mocked method. For example we can use the >>> operator followed by a list of return values ['abc', 'def', 'ghi']. On the first invocation abc is return, the second invocation returns def and the third (and following) invocation(s) return ghi.

In the following specification we have a class under test StringUtil. The class has a dependency on an implementation of the Calculator interface. We mock this interface in our specification. We expect the calculateSize method is invoked 5 times, but we only provide 3 values for the invocations. This means the first time 1 is used, the second time 3 is used and the remaining invocations get the value 4:

package com.mrhaki.spock

@Grab('org.spockframework:spock-core:1.0-groovy-2.4')
import spock.lang.Specification
import spock.lang.Subject

class SampleSpec extends Specification {

    @Subject
    def util = new StringUtil()

    def "Calculate sizes of String values"() {
        given:
        def calculator = Mock(Calculator)
        util.calculator = calculator

        when:
        def total = util.size('one', 'two', 'three', 'four', 'five')

        then:
        5 * calculator.calculateSize(_) >>> [1,3,4]

        total == 1 + 3 + 4 + 4 + 4
    }

}

class StringUtil {
    def calculator

    int size(final String[] s) {
        s.sum { calculator.calculateSize(it) }
    }
}

interface Calculator {
    int calculateSize(final String s)
}

Written with Spock 1.0-groovy-2.4.

Original blog post written on September 21, 2015.

Change Return Value of Mocked or Stubbed Service Based On Argument Value

My colleague Albert van Veen wrote a blog post about Using ArgumentMatchers with Mockito. The idea is to let a mocked or stubbed service return a different value based on the argument passed into the service. This is inspired me to write the same sample with Spock.

Spock already has built-in mock and stub support, so first of all we don’t need an extra library to support mocking and stubbing. We can easily create a mock or stub with the Mock() and Stub() methods. We will see usage of both in the following examples.

In the first example we simply return true or false for ChocolateService.doesCustomerLikesChocolate() in the separate test methods.

import spock.lang.*

public class CandyServiceSpecification extends Specification {

    private ChocolateService chocolateService = Mock()
    private CandyService candyService = new CandyServiceImpl()
 
    def setup() {
        candyService.chocolateService = chocolateService
    }

    def "Customer Albert really likes chocolate"() {
        given:
        final Customer customer = new Customer(firstName: 'Albert')

        and: 'Mock returns true'
        1 * chocolateService.doesCustomerLikesChocolate(customer) >> true
        
        expect: 'Albert likes chocolate'
        candyService.getCandiesLikeByCustomer(customer).contains Candy.CHOCOLATE
    }

    def "Other customer do not like chocolate"() {
        given:
        final Customer customer = new Customer(firstName: 'Any other firstname')

        and: 'Mock returns false'
        1 * chocolateService.doesCustomerLikesChocolate(customer) >> false
        
        expect: 'Customer does not like chocolate'
        !candyService.getCandiesLikeByCustomer(customer).contains(Candy.CHOCOLATE)
    }

}

In the following example we mimic the ArgumentMatcher and this time we use a stub instead of mock.

import spock.lang.*

public class CandyServiceSpecification extends Specification {

    private CandyService candyService = new CandyServiceImpl()
 
    def setup() {
        candyService.chocolateService = Stub(ChocolateService) {
            getCandiesLikeByCustomer(_) >> { Customer customer ->
                customer?.firstName == 'Albert'
            }
        }
    }

    def "Customer Albert really likes chocolate"() {
        given:
        final Customer customer = new Customer(firstName: 'Albert')
        
        expect: 'Albert likes chocolate'
        candyService.getCandiesLikeByCustomer(customer).contains Candy.CHOCOLATE
    }

    def "Other customer do not like chocolate"() {
        given:
        final Customer customer = new Customer(firstName: 'Any other firstname')
        
        expect: 'Customer does not like chocolate'
        !candyService.getCandiesLikeByCustomer(customer).contains(Candy.CHOCOLATE)
    }

}

Code written with Spock 0.7-groovy-2.0

Original blog post written on May 17, 2013.

Custom Default Responses for Stubs

Although I couldn’t make it to Gr8Conf EU this year, I am glad a lot of the presentations are available as slide decks and videos. The slide deck for the talk Interesting nooks and crannies of Spock you (may) have never seen before by Marcin Zajączkowski is very interesting. This is really a must read if you use Spock (and why shouldn’t you) in your projects. One of the interesting things is the ability to change the response for methods in a class that is stubbed using Spock’s Stub method, but have no explicit stubbed method definition.

So normally when we create a stub we would add code that implements the methods from the stubbed class. In our specification the methods we have written are invoked instead of the original methods from the stubbed class. By default if we don’t override a method definition, but it is used in the specification, Spock will try to create a response using a default response strategy. The default response strategy for a stub is implemented by the class EmptyOrDummyResponse. For example if a method has a return type Message then Spock will create a new instance of Message and return it to be used in the specification. Spock also has a ZeroOrNullResponse response strategy. With this strategy null is returned for our method that returns the Message type.

Both response strategies implement the IDefaultResponse interface. We can write our own response strategy by implementing this interface. When we use the Stub method we can pass an instance of our response strategy with the defaultResponse named argument of the method. For example: MessageProvider stub = Stub(defaultResponse: new CustomResponse()). We implement the respond method of IDefaultResponse to write a custom response strategy. The method gets a IMockInvocation instance. We can use this instance to check for example the method name, return type, arguments and more. Based on this we can write code to return the response we want.

In the following example we have a Spock specification where we create a stub using the default response strategy, the ZeroOrNullResponse strategy and a custom written response strategy:

package com.mrhaki.spock

@Grab('org.spockframework:spock-core:1.0-groovy-2.4')
import spock.lang.Specification
import spock.lang.Subject
import org.spockframework.mock.ZeroOrNullResponse
import org.spockframework.mock.IDefaultResponse
import org.spockframework.mock.IMockInvocation

class SampleSpec extends Specification {

    def """stub default response returns
           instance of Message created with default constructor"""() {
        given: 'Use default response strategy EmptyOrDummyResponse'
        final MessageProvider messageProvider = Stub()
        final Sample sample = new Sample(messageProvider)

        expect:
        sample.sampleMessage == 'Sample says: default'
    }

    def "stub default reponse returns null with ZeroOrNullResponse"() {
        given: 'Use default response strategy of ZeroOrNullResponse'
        final MessageProvider messageProvider =
                Stub(defaultResponse: ZeroOrNullResponse.INSTANCE)
        final Sample sample = new Sample(messageProvider)

        when:
        sample.sampleMessage

        then: 'messageProvider.message returns null'
        thrown(NullPointerException)
    }

    def """stub default response returns
           Message object with initialized text property
           from StubMessageResponse"""() {
        given: 'Use custom default response strategy'
        final MessageProvider messageProvider =
                Stub(defaultResponse: new StubMessageResponse())
        final Sample sample = new Sample(messageProvider)

        expect:
        sample.sampleMessage == 'Sample says: *STUB MESSAGE TEXT*'
    }

}

/**
 * Class to test with a dependency on MessageProvider
 * that is stubbed in the specification.
 */
class Sample {
    private final MessageProvider messageProvider

    Sample(final MessageProvider messageProvider) {
        this.messageProvider = messageProvider
    }

    String getSampleMessage() {
        "Sample says: ${messageProvider.message.text}"
    }

    String sampleMessage(String prefix) {
        "Sample says: ${messageProvider.getMessageWithPrefix(prefix).text}"
    }
}

/**
 * Work with messages. This interface is stubbed
 * in the specification.
 */
interface MessageProvider {
    Message getMessage()
    Message getMessageWithPrefix(String prefix)
}

/**
 * Supporting class for MessageProvider.
 */
class Message {
    String text = 'default'
}

/**
 * Custom default response strategy.
 * When a method has a Message return type then we
 * create an instance of Message with a custom text
 * property value.
 * Otherwise rely on default behaviour.
 */
class StubMessageResponse implements IDefaultResponse {
    @Override
    Object respond(IMockInvocation invocation) {
        // If return type of method is Message we create
        // a new Message object with a filled text property.
        if (invocation.method.returnType == Message) {
            return new Message(text: '*STUB MESSAGE TEXT*')
        }

        // Otherwise use default response handler for Stubs.
        return ZeroOrNullResponse.INSTANCE.respond(invocation)
    }
}

Written with Spock 1.0-groovy-2.4.

Original blog post written on September 16, 2016.

Writing Assertions for Arguments Mock Methods

My colleague Arthur Arts has written a blog post Tasty Test Tip: Using ArgumentCaptor for generic collections with Mockito. This inspired me to do the same in Spock. With the ArgumentCaptor in Mockito the parameters of a method call to a mock are captured and can be verified with assertions. In Spock we can also get a hold on the arguments that are passed to method call of a mock and we can write assertions to check the parameters for certain conditions.

When we create a mock in Spock and invoke a method on the mock the arguments are matched using the equals() implementation of the argument type. If they are not equal Spock will tell us by showing a message that there are too few invocations of the method call. Let’s show this with an example. First we create some classes we want to test:

package com.mrhaki.spock

public class ClassUnderTest {

    private final Greeting greeting

    ClassUnderTest(final Greeting greeting) {
        this.greeting = greeting
    }

    String greeting(final List<Person> people) {
        greeting.sayHello(people)
    }
}


package com.mrhaki.spock

interface Greeting {
    String sayHello(final List<Person> people)
}


package com.mrhaki.spock

@groovy.transform.Canonical
class Person {
    String name
}    

Now we can write a Spock specification to test ClassUnderTest. We will now use the default matching of arguments of a mock provided by Spock.

package com.mrhaki.spock

import spock.lang.Specification

class SampleSpecification extends Specification {

    final ClassUnderTest classUnderTest = new ClassUnderTest()

    def "check sayHello is invoked with people in greeting method"() {
        given:
        final Greeting greeting = Mock()
        classUnderTest.greeting = greeting

        and:
        final List<Person> people = ['mrhakis', 'hubert'].collect { new Person(name: it) }

        when:
        final String greetingResult = classUnderTest.greeting(people)

        then:
        1 * greeting.sayHello([new Person(name: 'mrhaki'), new Person(name: 'hubert')])
    }

}

When we execute the specification we get a failure with the message that there are too few invocations:

...
Too few invocations for:

1 * greeting.sayHello([new Person(name: 'mrhaki'), new Person(name: 'hubert')])   (0 invocations)

Unmatched invocations (ordered by similarity):

1 * greeting.sayHello([com.jdriven.spock.Person(mrhakis), com.jdriven.spock.Person(hubert)])
...

To capture the arguments we have to use a different syntax for the method invocation on the mock. This time we define the method can be invoked with any number of arguments ((*_)) and then use a closure to capture the arguments. The arguments are passed to the closure as a list. We can then get the argument we want and write an assert statement.

package com.mrhaki.spock

import spock.lang.Specification

class SampleSpecification extends Specification {

    final ClassUnderTest classUnderTest = new ClassUnderTest()

    def "check sayHello is invoked with people in greeting method"() {
        given:
        final Greeting greeting = Mock()
        classUnderTest.greeting = greeting

        and:
        final List<Person> people = ['mrhakis', 'hubert'].collect { new Person(name: it) }

        when:
        final String greetingResult = classUnderTest.greeting(people)

        then:
        1 * greeting.sayHello(*_) >> { arguments ->
            final List<Person> argumentPeople = arguments[0]
            assert argumentPeople == [new Person(name: 'mrhaki'), new Person(name: 'hubert')]
        }
    }

}

We run the specification again and it will fail again (of course), but this time we get an assertion message:

...
Condition not satisfied:

argumentPeople == [new Person(name: 'mrhaki'), new Person(name: 'hubert')]
|              |   |                           |
|              |   |                           com.jdriven.spock.Person(hubert)
|              |   com.jdriven.spock.Person(mrhaki)
|              false
[com.jdriven.spock.Person(mrhakis), com.jdriven.spock.Person(hubert)]

    at com.jdriven.spock.SampleSpecification.check sayHello is invoked with people in greeting me\
thod_closure2(SampleSpecification.groovy:25)
...

Code written with Spock 0.7-groovy-2.0

Original blog post written on May 17, 2013.

Using Mock Method Arguments in Response

When we mock or stub methods we can use the method arguments passed to the method in the response for the mocked or stubbed method. We must write a closure after the rightShift operator (>>) and the closure arguments will resemble the arguments of the mocked or stubbed method. Alternatively we can use a single non-typed argument in the closure and this will contains the method argument list.

Let’s create a specification where we use this feature. In the following sample we use a mock for the AgeService used in the class under test. The method allowedMaxTime() is invoked by the class under test and basically should return the maximum hour of the day a show can be broadcasted. In our specification we use the name of the show to return different values during the test.

package com.mrhaki.spock

@Grab('org.spockframework:spock-core:0.7-groovy-2.0')
import spock.lang.*

class SampleSpec extends Specification {

    final ClassUnderTest classUnderTest = new ClassUnderTest()

    @Unroll
    def "show #name with start time 21h is #expected to show"() {
        setup:
        final AgeService ageService = Mock()
        classUnderTest.ageService = ageService

        when:
        final boolean allowed = classUnderTest.listing(
            new Show(name: name, startTime: 21)
        ) 

        then:
        1 * ageService.allowedMaxTime(_ as Show) >> { Show show ->
            show.name.toLowerCase().contains('kids') ? 10 : 23
        }
        // Alternative syntax with a non-typed closure argument:
        //1 * ageService.allowedMaxTime(_ as Show) >> { arguments ->
        //    arguments[0].name.toLowerCase().contains('kids') ? 10 : 23
        //}

        allowed == expected

        where:
        name            || expected
        'Kids rules'    || false
        'Sports united' || true
    }

}

/* Supporting classes and interface */

class ClassUnderTest {

    AgeService ageService

    boolean listing(final Show show) {
        final int hour = ageService.allowedMaxTime(show)
        show.startTime <= hour
    }
}

interface AgeService {
    int allowedMaxTime(Show show)
}

@groovy.transform.Canonical
class Show {
    String name
    int startTime
}

Code written with Spock 0.7-groovy-2.0.

Original blog post written on September 24, 2013.

Assign Multiple Data Variables from Provider

We can write data driven tests with Spock. We can specify for example a data table or data pipes in a where: block. If we use a data pipe we can specify a data provider that will return the values that are used on each iteration. If our data provider returns multiple results for each row we can assign them immediatelly to multiple variables. We must use the syntax [var1, var2, var3] << providerImpl to assign values to the data variables var1, var2 and var3. We know from Groovy the multiple assignment syntax with parenthesis ((var1, var2, var3)), but with Spock we use square brackets.

In the following sample specification we have a simple feature method. The where: block shows how we can assign the values from the provider to multiple data variables. Notice we can skip values from the provider by using a _ to ignore the value.

package com.mrhaki.spock

@Grab('org.spockframework:spock-core:0.7-groovy-2.0')
import spock.lang.*

class MultiDataVarSpec extends Specification {

    @Unroll("#value as upper case is #expected")
    def "check upper case value of String"() {
        expect:
        value.toUpperCase() == expected

        where:
        // Multi data variables value and expected,
        // will be filled with elements from a row
        // on each iteration. The first element of each
        // row is ignored.
        // E.g. on first iteration:
        // value = 'abc'
        // and expected = 'ABC'
        [_, value, expected] << [
            [1, 'abc', 'ABC'],
            [2, 'def', 'DEF'], 
            [3, '123', '123']
        ]
    }


}

Code written with Spock 0.7-groovy-2.0 and Groovy 2.3.3.

Original blog post written on June 25, 2014.

Write Our Own Data Provider

We can use data pipes to write data driven tests in Spock. A data pipe (<<) is fed by a data provider. We can use Collection objects as data provider, but also String objects and any class that implements the Iterable interface. We can write our own data provider class if we implement the Iterable interface.

In the following sample code we want to test the female property of the User class. We have the class MultilineProvider that implements the Iterable interface. The provider class accepts a multiline String value and returns the tokenized result of each line in each iteration.

package com.mrhaki.spock

@Grab('org.spockframework:spock-core:0.7-groovy-2.0')
import spock.lang.*

class ProviderSampleSpec extends Specification {

    @Unroll("Gender #gender for #name is #description")
    def "check if user is female or male based on gender value"() {
        given:
        def userData = '''\
            1;mrhaki;M;false
            2;Britt;F;true'''

        expect:
        new User(name: name, gender: gender).female == Boolean.valueOf(expected)

        where:
        [_, name, gender, expected] << new MultilineProvider(source: userData)

        // Extra data variable to be used in
        // @Unroll description.
        description = expected ? 'female' : 'not female'
    }

}

/**
 * Class under test.
 */
class User {
    String name, gender

    Boolean isFemale() {
        gender == 'F'
    }
}

/**
 * Class implements Iterable interface so
 * it can be used as data provider.
 */
class MultilineProvider implements Iterable {
    def source
    def lines
    def separator = ';'

    private int counter

    /**
     * Set multiline String as source
     * and transform to a List of String
     * values and assign to the lines
     * property.
     */
    void setSource(source) {
        this.source = source.stripIndent()
        lines = this.source.readLines()
    }

    @Override
    Iterator iterator() {
        [
            hasNext: {
                counter < lines.size()
            },
            next: {
                lines[counter++].tokenize(separator)
            }
        ] as Iterator
    }
}

Code written with Spock 0.7-groovy-2 and Groovy 2.3.3.

Original blog post written on June 25, 2014.

Extra Data Variables for Unroll Description

Spock’s unroll feature is very powerful. The provider data variables can be used in the method description of our specification features with placeholders. For each iteration the placeholders are replaced with correct values. This way we get a nice output where we immediately can see the values that were used to run the code. Placeholders are denoted by a hash sign (#) followed by the variable name. We can even invoke no-argument methods on the variable values or access properties. For example if we have a String value we could get the upper case value with #variableName.toUpperCase(). If we want to use more complex expressions we must introduce a new data variable in the where block. The value of the variable will be determined for each test invocation and we can use the result as a value in the method description.

package com.mrhaki.spock

import spock.lang.*

class SampleSpec extends Specification {

    @Unroll
    def "check if '#value' is lower case"() {
        expect:
        value.every { (it as char).isLowerCase() } == result

        where:
        value || result
        'A'   || false
        'Ab'  || false
        'aB'  || false
        'a'   || true
        'ab'  || true
    }

}

If we look at the output of the tests we see the method names are not really representing the code we test. For example we can not see if the value was lower case or not.

We rewrite the specification and add a new data variable unrollDescription in the where block. We then refer to this variable in our method name description.

package com.mrhaki.spock

import spock.lang.*

class SampleSpec extends Specification {

    @Unroll
    // Alternatively syntax as 
    // unroll annotation argument:
    // @Unroll("'#value' is #unrollDescription")
    def "'#value' is #unrollDescription"() {
        expect:
        value.every { (it as char).isLowerCase() } == result

        where:
        value || result
        'A'   || false
        'Ab'  || false
        'aB'  || false
        'a'   || true
        'ab'  || true

        unrollDescription = result ? 'lower case' : 'not lower case'
    }

}

When we look at the output we now have more descriptive method names:

This post is inspired by the great Idiomatic Spock talk by Rob Fletcher at Gr8Conf 2014 Europe.

Code written with Spock 0.7 for Groovy 2.

Original blog post written on June 16, 2014.

Ignore Specifications Based On Conditions

We can use the @Ignore and @IgnoreRest annotation in our Spock specifications to not run the annotated specifications or features. With the @IgnoreIf annotation we can specify a condition that needs to evaluate to true to not run the feature or specification. The argument of the annotation is a closure. Inside the closure we can access three extra variables: properties (Java system properties), env (environment variables) and javaVersion.

In the following Spock specification we have a couple of features. Each feature has the @IgnoreIf annotation with different checks. We can use the extra variables, but we can also invoke our own methods in the closure argument for the annotation:

package com.mrhaki.spock

import spock.lang.*

class SampleRequiresSpec extends Specification {

    private static boolean isOsWindows() {
        System.properties['os.name'] == 'windows'
    }

    @IgnoreIf({ Boolean.valueOf(properties['spock.ignore.longRunning']) })
    def "run spec if Java system property 'spock.ignore.longRunning' is not set or false"() {
        expect:
        true
    }

    @IgnoreIf({ Boolean.valueOf(env['SPOCK_IGNORE_LONG_RUNNING']) })
    def "run spec if environment variable 'SPOCK_IGNORE_LONG_RUNNING' is not set or false"() {
        expect:
        true
    }

    @IgnoreIf({ javaVersion < 1.7 })
    def "run spec if run in Java 1.7 or higher"() {
        expect:
        true
    }

    @IgnoreIf({ javaVersion != 1.7 })
    def "run spec if run in Java 1.7"() {
        expect:
        true
    }

    @IgnoreIf({ isOsWindows() })
    def "run only if run on non-windows operating system"() {
        expect:
        true
    }

}

When we run our specification with Java 1.8 and do not set the Java system property spock.ignore.longRunning or we set the value to false and we do not set the environment variable SPOCK_IGNORE_LONG_RUNNING or give it the value false we can see that some features are ignored:

Now we run on Java 1.7, Windows operating system and set the Java system property spock.ignore.longRunning with the value true and the environment variable SPOCK_IGNORE_LONG_RUNNING with the value true. The resulting report shows the specifications that are ignored and those that are executed:

Code written with Spock 0.7-groovy-2.

Original blog post written on June 20, 2014.

Only Run Specs Based On Conditions

In a previous blog post we have seen the IgnoreIf extension. There is also a counterpart: the Requires extension. If we apply this extension to a feature method or specification class than the method or whole class is executed when the condition for the @Requires annotation is true. If the condition is false the method or specification is not executed. As a value for the @Requires annotation we must specify a closure. In the closure Spock adds some properties we can use for our conditions:

  • jvm can be used to check a Java version or compatibility.
  • sys returns the Java system properties.
  • env used to access environment variables.
  • os can be used to check for operating system names.
  • javaVersion has the Java version as BigDecimal, eg. 1.8.

In the following example we use the @Requires annotation with different conditions:

package com.mrhaki.spock

import spock.lang.Requires
import spock.lang.Specification

class RequiresSampleSpec extends Specification {

    @Requires({ Boolean.valueOf(sys['spock.longRunning']) })
    def "run spec if Java system property 'spock.longRunning' is true"() {
        expect:
        true
    }

    @Requires({ Boolean.valueOf(env['SPOCK_LONG_RUNNING']) })
    def "run spec if environment variable 'SPOCK_LONG_RUNNING' is true"() {
        expect:
        true
    }

    @Requires({ javaVersion >= 1.7 })
    def "run spec if run in Java 1.7 or higher"() {
        expect:
        true
    }

    @Requires({ jvm.isJava8() })
    def "run spec if run in Java 1.8"() {
        expect:
        true
    }

    @Requires({ os.isWindows() })
    def "run only if run on windows operating system"() {
        expect:
        true
    }

}

If we have the same condition to be applied for all feature methods in a specification we can use the @Requires annotation at the class level:

package com.mrhaki.spock

import spock.lang.Requires
import spock.lang.Specification

@Requires({ jvm.isJava7Compatible() })
class RequiresSpec extends Specification {

    def "all feature methods run only if JVM is Java 7 compatible"() {
        expect:
        true
    }

}

Written with Spock 1.0-groovy-2.4.

Original blog post written on September 04, 2015.

Indicate Class Under Test with Subject Annotation

If we write a specification for a specific class we can indicate that class with the @Subject annotation. This annotation is only for informational purposes, but can help in making sure we understand which class we are writing the specifications for. The annotation can either be used at class level or field level. If we use the annotation at class level we must specify the class or classes under test as argument for the annotation. If we apply the annotation to a field, the type of the field is used as the class under test. The field can be part of the class definition, but we can also apply the @Subject annotation to fields inside a feature method.

In the following example Spock specification we write a specification for the class Greet. The definition of the Greet class is also in the code listing. We use the @Subject annotation on the field greet to indicate this instance of the Greet class is the class we are testing here. The code also works without the @Subject annotation, but it adds more clarity to the specification.

package com.mrhaki.spock

@Grab('org.spockframework:spock-core:0.7-groovy-2.0')
import spock.lang.*

// The @Subject annotation can also be applied at class level.
// We must specify the class or classes as arguments:
// @Subject([Greet])
class GreetSpec extends Specification {

    // The greet variable of type Greet is the
    // class we are testing in this specification.
    // We indicate this with the @Subject annotation.
    @Subject
    private Greet greet = new Greet(['Hi', 'Hello'])

    // Simple specification to test the greeting method.
    def "greeting should return a random salutation followed by name"() {
        when:
        final String greeting = greet.greeting('mrhaki')

        then:
        greeting == 'Hi, mrhaki' || greeting == 'Hello, mrhaki'
    }

}

/**
 * Class which is tested in the above specification.
 */
@groovy.transform.Immutable
class Greet {

    final List<String> salutations

    String greeting(final String name) {
        final int numberOfSalutations = salutations.size()
        final int selectedIndex = new Random().nextInt(numberOfSalutations)
        final String salutation = salutations.get(selectedIndex)

        "${salutation}, ${name}"
    }

}

Code written with Spock 0.7-groovy-2.0 and Groovy 2.3.7.

Original blog post written on October 13, 2014.

Undo MetaClass Changes

Spock has the extension ConfineMetaClassChanges that can be used to encapsulate meta class changes to a feature method or specification. We must apply the annotation @ConfineMetaClassChanges to a feature method or to a whole specification to use this extension. Spock replaces the original meta class with a new one before a feature method is executed. After execution of a feature method the original meta class is used again. We could this by hand using the setup, setupSpec and their counter parts cleanup and cleanupSpec, but using this extension is so much easier. We must specify the class or classes whose meta class changes need to be confined as the value for the annotation.

In the following example we add a new method asPirate to the String class. We apply the @ConfineMetaClassChanges to a method. This means the new method is only available inside the feature method.

package com.mrhaki.spock

import spock.lang.Specification
import spock.lang.Stepwise
import spock.util.mop.ConfineMetaClassChanges

// We use @Stepwise in this specification
// to show that changes in the metaClass
// done in the first feature method do not
// work in the second feature method.
@Stepwise
class PirateTalkSpec extends Specification {

    // After this feature method is finished,
    // the metaClass changes to the given
    // class (String in our case) are reverted.
    @ConfineMetaClassChanges([String])
    def "talk like a pirate"() {
        setup:
        String.metaClass.asPirate = { ->
            return "Yo-ho-ho, ${delegate}"
        }

        expect:
        'mrhaki'.asPirate() == 'Yo-ho-ho, mrhaki'
    }

    // In this feature method we no longer
    // can use the asPirate() method that was
    // added to the metaClass.
    def "keep on talking like a pirate"() {
        when:
        'hubert'.asPirate()

        then:
        thrown(MissingMethodException)
    }

}

In the following example code we apply the @ConfineMetaClassChanges to the whole class. Now we see that the new method asPirate is still available in another feature method, than the one that defined it.

package com.mrhaki.spock

import spock.lang.Specification
import spock.lang.Stepwise
import spock.util.mop.ConfineMetaClassChanges

// We use @Stepwise in this specification
// to show that changes in the metaClass
// done in the first feature method still
// work in the second.
@Stepwise
// If set a class level then the
// changes done to the metaClass of
// the given class (String in our
// example) are reverted after the
// specification is finished.
@ConfineMetaClassChanges([String])
class PirateTalkSpec extends Specification {

    def "talk like a pirate"() {
        setup:
        String.metaClass.asPirate = { ->
            return "Yo-ho-ho, ${delegate}"
        }

        expect:
        'mrhaki'.asPirate() == 'Yo-ho-ho, mrhaki'
    }

    def "keep on talking like a pirate"() {
        expect:
        'hubert'.asPirate() == 'Yo-ho-ho, hubert'
    }
}

This post is very much inspired by this blog post of my colleague Albert van Veen.

Written with Spock 1.0-groovy-2.4.

Original blog post written on September 03, 2015.

Undo Changes in Java System Properties

If we need to add a Java system property or change the value of a Java system property inside our specification, then the change is kept as long as the JVM is running. We can make sure that changes to Java system properties are restored after a feature method has run. Spock offers the RestoreSystemProperties extension that saves the current Java system properties before a method is run and restores the values after the method is finished. We use the extension with the @RestoreSystemProperties annotation. The annotation can be applied at specification level or per feature method.

In the following example we see that changes to the Java system properties in the first method are undone again in the second method:

package com.mrhaki.spock

import spock.lang.Specification
import spock.lang.Stepwise
import spock.util.environment.RestoreSystemProperties

// Use Stepwise extension so the order
// of method invocation is guaranteed.
@Stepwise
class SysSpec extends Specification {

    // Changes to Java system properties in this
    // method are undone once the method is done.
    @RestoreSystemProperties
    def "first method adds a Java system property"() {
        setup:
        System.properties['spockAdded'] = 'Spock is gr8'

        expect:
        System.properties['spockAdded'] == 'Spock is gr8'
    }

    def "second method has no access to the new property"() {
        expect:
        !System.getProperty('spockAdded')
    }

}

Written with Spock 1.0-groovy-2.4.

Original blog post written on September 04, 2015.

Auto Cleanup Resources

Spcok has a lot of nice extensions we can use in our specifications. The AutoCleanup extension makes sure the close() method of an object is called each time a feature method is finished. We could invoke the close() method also from the cleanup method in our specification, but with the @AutoCleanup annotation it is easier and immediately shows our intention. If the object we apply the annotation to doesn’t have a close() method to invoke we can specify the method name as the value for the annotation. Finally we can set the attribute quiet to true if we don’t want to see any exceptions that are raised when the close() method (or custom method name, that is specified) is invoked.

In the following example code we have a specification that is testing the WatchService implementation. The implementation also implements the Closeable interface, which means we can use the close() method to cleanup the object properly. We also have a custom class WorkDir with a delete() method that needs to be invoked.

package com.mrhaki.spock

import spock.lang.AutoCleanup
import spock.lang.Specification

import java.nio.file.FileSystems
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
import java.nio.file.WatchKey
import java.nio.file.WatchService
import java.util.concurrent.TimeUnit

import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE

class WatchSpec extends Specification {

    // Use close() method of WatchService
    // when feature method is done.
    @AutoCleanup
    private WatchService watchService

    // Use delete() method of WorkDir class
    // when feature method is done.
    // If the quiet attribute is true, then
    // exceptions from the delete() method are
    // not shown, otherwise exceptions are reported.
    @AutoCleanup(value = 'delete', quiet = true)
    private WorkDir testPath = new WorkDir('test-dir')

    def setup() {
        // Get new watch service.
        watchService = FileSystems.default.newWatchService()

        // Register for events when a new file is created
        // in the testPath directory.
        testPath.path.register(watchService, ENTRY_CREATE)
    }

    def "get notification when file is created"() {
        given:
        final Path testFile = testPath.path.resolve('test-file')
        testFile << 'sample'

        and:
        final WatchKey watchKey = watchService.poll(10, TimeUnit.SECONDS)

        when:
        final events = watchKey.pollEvents()

        then:
        events.size() == 1
        events[0].kind() == ENTRY_CREATE

        cleanup:
        Files.delete(testFile)
    }

}

class WorkDir {

    private final Path path

    WorkDir(final String dir) {
        path = Paths.get(dir)
        Files.createDirectories(path)
    }

    Path getPath() {
        path
    }

    void delete() {
        Files.deleteIfExists(path)
    }

}

Written with Spock 1.0-groovy-2.4.

Original blog post written on September 01, 2015.

Including or Excluding Specifications Based On Annotations

One of the lesser known and documented features of Spock if the external Spock configuration file. In this file we can for example specify which specifications to include or exclude from a test run. We can specify a class name (for example a base specification class, like DatabaseSpec) or an annotation. In this post we see how to use annotations to have some specifications run and others not.

The external Spock configuration file is actually a Groovy script file. We must specify a runner method with a closure argument where we configure basically the test runner. To include specification classes or methods with a certain annotation applied to them we configure the include property of the test runner. To exclude a class or method we use the exclude property. Because the configuration file is a Groovy script we can use everything Groovy has to offer, like conditional statements, println statements and more.

Spock looks for a file named SpockConfig.groovy in the classpath of the test execution and in in the USER_HOME/.spock directory. We can also use the Java system property spock.configuration with a file name for the configuration file.

In the following example we first define a simple annotation Remote. This annotation can be applied to a class or method:

package com.mrhaki.spock

import java.lang.annotation.ElementType
import java.lang.annotation.Retention
import java.lang.annotation.RetentionPolicy
import java.lang.annotation.Target

@Target([ElementType.TYPE, ElementType.METHOD])
@Retention(RetentionPolicy.RUNTIME)
@interface Remote {
}

We write a simple Spock specification where we apply the Remote annotation to one of the methods:

package com.mrhaki.spock

import spock.lang.Specification

class WordRepositorySpec extends Specification {

    @Remote  // Apply our Remote annotation.
    def "test remote access"() {
        given:
        final RemoteAccess access = new RemoteAccess()

        expect:
        access.findWords('S') == ['Spock']
    }

    def "test local access"() {
        given:
        final LocalAccess access = new LocalAccess()

        expect:
        access.findWords('S') == ['Spock']
    }

}

Next we create a Spock configuration file:

import com.mrhaki.spock.Remote

runner {
    // This is Groovy script and we
    // add arbitrary code.
    println "Using RemoteSpockConfig"

    // Include only test classes or test
    // methods with the @Remote annotation
    include Remote

    // Alternative syntax
    // to only look for annotations.
    // include {
    //     annotation Remote
    // }


    // We can also add a condition in
    // the configuration file.
    // In this case we check for a Java
    // system property and if set the
    // specs with @Remote are not run.
    if (System.properties['spock.ignore.Remote']) {
        exclude Remote
    }
}

When we run the WordRepositorySpec and our configuration file is on the classpath only the specifications with the @Remote annotation are executed. Let’s apply this in a simple Gradle build file. In this case we save the configuration file as src/test/resources/RemoteSpockConfig.groovy, we create a new test task remoteTest and set the Java system property spock.configuration:

apply plugin: 'groovy'

repositories {
    jcenter()
}

dependencies {
    compile 'org.codehaus.groovy:groovy-all:2.4.4'
    testCompile 'org.spockframework:spock-core:1.0-groovy-2.4'
}

// New test task with specific
// Spock configuration file.
task remoteTest(type: Test) {
    // This task belongs to Verification task group.
    group = 'Verification'

    // Set Spock configuration file when running
    // this test task.
    systemProperty 'spock.configuration', 'RemoteSpockConfig.groovy'
}

Now when we execute the Gradle test task all specifications are executed:

And when we run remoteTest only the specification with the @Remote annotation are executed:

Written with Gradle 2.6 and Spock 1.0-groovy-2.4.

The code is available on Github

Original blog post written on August 27, 2015.

Optimize Run Order Test Methods

Spock is able to change the execution order of test methods in a specification. We can tell Spock to re-run failing methods before successful methods. And if we have multiple failing or successful tests, than first run the fastest methods, followed by the slower methods. This way when we re-run the specification we immediately see the failing methods and could stop the execution and fix the errors. We must set the property optimizeRunOrder in the runner configuration of the Spock configuration file. A Spock configuration file with the name SpockConfig.groovy can be placed in the classpath of our test execution or in our USER_HOME/.spock directory. We can also use the Java system property spock.configuration and assign the filename of our Spock configuration file.

In the following example we have a specification with different methods that can be successful or fail and have different durations when executed:

package com.mrhaki.spock

import spock.lang.Specification
import spock.lang.Subject

class SampleSpec extends Specification {

    @Subject
    private Sample sample = new Sample()

    def "spec1 - slowly should return name property value"() {
        given:
        sample.name = testValue

        expect:
        sample.slowly() == testValue

        where:
        testValue = 'Spock rules'
    }

    def "spec2 - check name property"() {
        given:
        sample.name = testValue

        expect:
        sample.name == testValue

        where:
        testValue = 'Spock is gr8'
    }

    def "spec3 - purposely fail test at random"() {
        given:
        sample.name = testValues[randomIndex]

        expect:
        sample.name == testValues[0]

        where:
        testValues = ['Spock rules', 'Spock is gr8']
        randomIndex = new Random().nextInt(testValues.size())
    }

    def "spec4 - purposely fail test slowly"() {
        given:
        sample.name = 'Spock is gr8'

        expect:
        sample.slowly() == 'Spock rules'
    }

    def "spec5 - purposely fail test"() {
        given:
        sample.name = 'Spock rules'

        expect:
        sample.name == 'Spock is gr8'
    }
}

class Sample {
    String name

    String slowly() {
        Thread.sleep(2000)
        name
    }
}

Let’s run our test where there is no optimised run order. We see the methods are executed as defined in the specification:

Next we create a Spock configuration file with the following contents:

runner {
    println "Optimize run order"
    optimizeRunOrder true
}

If we re-run our specification and have this file in the classpath we already see the order of the methods has changed. The failing tests are at the top and the successful tests are at the bottom. The slowest test method is last:

Another re-run has optimised the order by running the slowest failing test after the other failing tests.

Spock keeps track of the failing and successful methods and their execution time in a file with the specification name in the USER_HOME/.spock/RunHistory directory. To reset the information we must delete the file from this directory.

Written with Spock 1.0-groovy-2.4.

Original blog post written on August 28, 2015.

Support for Hamcrest Matchers

Spock has support for Hamcrest matchers and adds some extra syntactic sugar. In an expect: block in a Spock specification method we can use the following syntax value Matcher. Let’s create a sample Spock specification and use this syntax with the Hamcrest matcher hasKey:

// File: SampleSpecification.groovy
package com.mrhaki.spock

@Grab('org.hamcrest:hamcrest-all:1.3')
import static org.hamcrest.Matchers.*

@Grab('org.spockframework:spock-core:0.7-groovy-2.0')
import spock.lang.Specification

class SampleSpecification extends Specification {

    def "sample usage of hamcrest matcher hasKey"() {
        given:
        final sampleMap = [name: 'mrhaki']

        expect:
        sampleMap hasKey('name')
        sampleMap not(hasKey('name')) // To show assertion message.
    }

}

We can run the code ($groovy SampleSpecification.groovy) and see in the output a very useful assertion message for the second matcher in the expect: block. We directly see what went wrong and what was expected.

$ groovy SampleSpecification.groovy
JUnit 4 Runner, Tests: 1, Failures: 1, Time: 210
Test Failure: sample usage of hamcrest matcher hasKey(com.mrhaki.spock.SampleSpecification)
Condition not satisfied:

sampleMap not(hasKey('name'))
|         |
|         false
[name:mrhaki]

Expected: not map containing ["name"->ANYTHING]
     but: was <{name=mrhaki}>

 at com.mrhaki.spock.SampleSpecification.sample usage of hamcrest matcher hasKey(SampleSpecificat\
ion.groovy:18)

With Spock we can rewrite the specification and use the static method that() in spock.util.matcher.HamcrestSupport as a shortcut for the Hamcrest assertThat() method. The following sample shows how we can use that(). With this method we can use the assertion outside an expect: or then: block.

// File: SampleSpecification.groovy
package com.mrhaki.spock

@Grab('org.hamcrest:hamcrest-all:1.3')
import static org.hamcrest.Matchers.*

@Grab('org.spockframework:spock-core:0.7-groovy-2.0')
import static spock.util.matcher.HamcrestSupport.*
import spock.lang.Specification

class SampleSpecification extends Specification {

    def "sample usage of hamcrest matcher hasKey"() {
        given:
        final sampleMap = [name: 'mrhaki']

        expect:
        that sampleMap, hasKey('name')
    }

}

Finally we can use the expect() method in spock.util.matcher.HamcrestSupport to add the assertion in a then: block. This improves readability of our specification.

// File: SampleSpecification.groovy
package com.mrhaki.spock

@Grab('org.hamcrest:hamcrest-all:1.3')
import static org.hamcrest.Matchers.*

@Grab('org.spockframework:spock-core:0.7-groovy-2.0')
import static spock.util.matcher.HamcrestSupport.*
import spock.lang.Specification

class SampleSpecification extends Specification {

    def "sample usage of hamcrest matcher hasKey"() {
        when:
        final sampleMap = [name: 'mrhaki']

        then:
        expect sampleMap, hasKey('name')
    }

}

Code written with Spock 0.7-groovy-2.0

Original blog post written on May 14, 2013.

Using a Custom Hamcrest Matcher

In a previous blog post we learned how we can use Hamcrest matchers. We can also create a custom matcher and use it in our Spock specification. Let’s create a custom matcher that will check if elements in a list are part of a range.

In the following specification we create the method inRange() which will return an instance of a Matcher object. This object must implement a matches() method and extra methods to format the description when the matcher fails. We use Groovy’s support to create a Map and turn it into an instance of BaseMatcher.

// File: SampleSpecification.groovy
package com.mrhaki.spock

@Grab('org.hamcrest:hamcrest-all:1.3')
import static org.hamcrest.Matchers.*
import org.hamcrest.*

@Grab('org.spockframework:spock-core:0.7-groovy-2.0')
import static spock.util.matcher.HamcrestSupport.*
import spock.lang.Specification

class SampleSpecification extends Specification {

    def "sample usage of custom hamcrest matcher"() {
        given:
        final list = [2,3,4]

        expect:
        that list, inRange(0..10)
        that list, not(inRange(0..3))
    }

    /**
     * Create custom Hamcrest matcher to check if a list has elements
     * that are contained in the define range.
     *
     * @param range Range to check if elements in the list are in this range.
     * @return Hamcrest matcher to check if elements in the list are part of the range.
     */
    private inRange(final range) {
        [
            matches: { list -> range.intersect(list) == list },
            describeTo: { description ->
                description.appendText("list be in range ${range}")
            },
            describeMismatch: { list, description ->
                description.appendValue(list.toListString()).appendText(" was not in range ${rang\
e}")
            }
        ] as BaseMatcher
    }

}

We can run the specification ($ groovy SampleSpecification.groovy) and everything should work and all tests must pass.

We change the code to see the description we have added. So we change that list, inRange(0..10) to that list, inRange(0..3). We run the specification again ($ groovy SampleSpecification.groovy) and look at the output:

JUnit 4 Runner, Tests: 1, Failures: 1, Time: 200
Test Failure: sample usage of custom hamcrest matcher(com.mrhaki.spock.SampleSpecification)
Condition not satisfied:

that list, inRange(0..3)
|    |
|    [2, 3, 4]
false

Expected: list be in range [0, 1, 2, 3]
     but: "[2, 3, 4]" was not in range [0, 1, 2, 3]

    at com.mrhaki.spock.SampleSpecification.sample usage of custom hamcrest matcher(SampleSpecifi\
cation.groovy:18)

Notice the output shows the text we have defined in the describeTo() and describeMismatch() methods.

Code written with Spock 0.7-groovy-0.2.

Original blog post written on May 14, 2013.