Spocklight Notebook
Spocklight Notebook
Hubert A. Klein Ikkink (mrhaki)
Buy on Leanpub

Table of Contents

About Me

I am born in 1973 and live in Tilburg, the Netherlands, with my 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.

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.

Getting Started

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
// 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.UserServiceSpecification" \
tests="4" time="0.707" timestamp="2010-06-29T18:17:24">
  <properties />
  <testcase classname="com.mrhaki.blog.UserServiceSpecification" name="Expect to count 0 users for fol\
lowing list null" time="0.152" />
  <testcase classname="com.mrhaki.blog.UserServiceSpecification" name="Expect to count 0 users for fol\
lowing list []" time="0.027" />
  <testcase classname="com.mrhaki.blog.UserServiceSpecification" name="Expect to count 1 users for fol\
lowing list [mrhaki]" time="0.0050" />
  <testcase classname="com.mrhaki.blog.UserServiceSpecification" name="Expect to count 2 users for fol\
lowing 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 post written on June 29, 2010

Assertions

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(CourseServiceS\
pec.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(CourseServiceS\
pec.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 post written on July 5, 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 post written on January 29, 2016

Group Assertions With verifyAll

We all know writing tests or specifications with Spock is fun. We can run our specifications and when one of our assertions in a feature method invalid, the feature method is marked as failed. If we have more than one assertion in our feature method, only the first assertion that fails is returned as an error. Any other assertion after a failing assertion are not checked. To let Spock execute all assertions and return all failing assertions at once we must use the verifyAll method. We pass a closure with all our assertions to the method. All assertions will be checked when use the verifyAll and if one or more of the assertions is invalid the feature method will fail.

In the following example specification we have 3 assertions in the feature method check all properties are valid. We don't use the verifyAll method in our first example.

// File: verifyall.groovy
@Grab('org.spockframework:spock-core:1.1-groovy-2.4')
import spock.lang.Specification
import spock.lang.Subject

class CourseSpec extends Specification {

    @Subject
    private course = new Course()
    
    void 'check all properties are valid'() {
        given:
        course.with {
            name = 'G'
            location = 'T'
            numberOfDays = 0
        }
    
        expect:
        with(course) {
            name.size() > 2
            location.size() > 2
            numberOfDays > 0
        }
    }

}

class Course {
    String name
    String location
    int numberOfDays
}

Let's see what happens when we don't use the verifyAll method and run the specification:

$ groovy verifyall.groovy
JUnit 4 Runner, Tests: 1, Failures: 1, Time: 28
Test Failure: check all properties are valid(CourseSpec)
Condition not satisfied:

name.size() > 2
|    |      |
G    1      false

 at CourseSpec.check all properties are valid_closure2(verifyall.groovy:21)
 at groovy.lang.Closure.call(Closure.java:414)
 at spock.lang.Specification.with(Specification.java:186)
 at CourseSpec.check all properties are valid(verifyall.groovy:20)

In the next example we use verifyAll to group the assertions for our course object:

// File: verifyall.groovy
@Grab('org.spockframework:spock-core:1.1-groovy-2.4')
import spock.lang.Specification
import spock.lang.Subject


class CourseSpec extends Specification {

    @Subject
    private course = new Course()
    
    void 'check all properties are valid'() {
        given:
        course.with {
            name = 'G'
            location = 'T'
            numberOfDays = 0
        }
    
        expect:
        with(course) {
            verifyAll {
                name.size() > 2
                location.size() > 2
                numberOfDays > 0
            }
        }
    }

}

class Course {
    String name
    String location
    int numberOfDays
}

We re-run the specification and now we get different output with all three assertions mentioned:

$ groovy verifyall.groovy
JUnit 4 Runner, Tests: 1, Failures: 1, Time: 26
Test Failure: check all properties are valid(CourseSpec)
Condition failed with Exception:

with(course) { verifyAll { name.size() > 2 location.size() > 2 numberOfDays > 0 } }

 at CourseSpec.check all properties are valid(verifyall.groovy:20)
Caused by: org.junit.runners.model.MultipleFailureException: There were 3 errors:
  org.spockframework.runtime.ConditionNotSatisfiedError(Condition not satisfied:

name.size() > 2
|    |      |
G    1      false
)
  org.spockframework.runtime.ConditionNotSatisfiedError(Condition not satisfied:

location.size() > 2
|        |      |
T        1      false
)
  org.spockframework.runtime.ConditionNotSatisfiedError(Condition not satisfied:

numberOfDays > 0
|            |
0            false
)
 at CourseSpec.$spock_feature_0_0_closure2$_closure3(verifyall.groovy:24)
 at CourseSpec.$spock_feature_0_0_closure2$_closure3(verifyall.groovy)
 at groovy.lang.Closure.call(Closure.java:414)
 at spock.lang.Specification.verifyAll(Specification.java:223)
 at CourseSpec.check all properties are valid_closure2(verifyall.groovy:21)
 at groovy.lang.Closure.call(Closure.java:414)
 at spock.lang.Specification.with(Specification.java:186)
 ... 1 more

Written with Spock 1.1-groovy-2.4.

Original post written on September 18, 2017

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 post written on January 21, 2011

Check No Exceptions Are Thrown At All

In a previous post we learned that we can check a specific exception is not thrown in our specification with the notThrown method. If we are not interested in a specific exception, but just want to check no exception at all is thrown, we must use the noExceptionThrown method. This method return true if the called code doesn't throw an exception.

In the following example we invoke a method (cook) that can throw an exception. We want to test the case when no exception is thrown:

package com.mrhaki.blog

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

class RecipeServiceSpec extends Specification {
    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: 'no exceptions must be thrown'
        noExceptionThrown()
    }
}

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
}

import groovy.transform.InheritConstructors

@InheritConstructors
class BurnedException extends RuntimeException {
}

@InheritConstructors
class InvalidDeviceException extends RuntimeException {
}

Written with Spock 1.0-groovy-2.4.

Original post written on September 30, 2016

Assert Elements In Collections In Any Order

Since Spock 2.1 we have 2 new operators we can use for assertions to check collections: =~ and ==~. We can use these operators with implementations of the Iterable interface when we want to check that a given collection has the same elements as an expected collection and we don’t care about the order of the elements. Without the new operators we would have to cast our collections to a Set first and than use the == operator.

The difference between the operators =~ and ==~ is that =~ is lenient and ==~ is strict. With the lenient match operator we expect that each element in our expected collection appears at least once in the collection we want to assert. The strict match operator expects that each element in our expected collection appears exactly once in the collection we want to assert.

In the following example we see different uses of the new operators and some other idiomatic Groovy ways to check elements in a collection in any order:

package mrhaki

import spock.lang.Specification;

class CollectionConditions extends Specification {

    void "check items in list are present in the same order"() {
        when:
        List<Integer> result = [1, 10, 2, 20]

        then:
        // List result is ordered so the items
        // are not the same as the expected List.
        result != [20, 10, 2, 1]
        result == [1, 10, 2, 20]

        // We can cast the result and expected list to Set
        // and now the contents and order is the same.
        result as Set == [20, 10, 2, 1] as Set
    }

    void "check all items in list are present in any order"() {
        when:
        List<Integer> result = [1, 10, 2, 20]

        then:
        result ==~ [20, 10, 2, 1]

        /* The following assert would fail:
           result ==~ [20, 10]

           Condition not satisfied:

           result ==~ [20, 10]
           |      |
           |      false
           [1, 10, 2, 20]

           Expected: iterable with items [<20>, <10>] in any order
                but: not matched: <1>*/

        // Negating also works
        result !==~ [20, 10]
    }

    void "lenient check all items in list are present in any order"() {
        when:
        List<Integer> result = [1, 1, 10, 2, 2, 20]

        then:
        // result has extra values 1, 2 but with lenient
        // check the assert is still true.
        result =~ [20, 10, 2, 1]

        /* The following assert would fail:

        result =~ [20, 10]

        Condition not satisfied:

        result =~ [20, 10]
        |      |
        |      false
        |      2 differences (50% similarity, 0 missing, 2 extra)
        |      missing: []
        |      extra: [1, 2]
        [1, 10, 2, 20] */

        // Negating works
        result !=~ [20, 10]
    }

    void "check at least one item in list is part of expected list in any order"() {
        when:
        List<Integer> result = [1, 10, 2, 20]

        then:
        result.any { i -> i in [20, 10]}
    }

    void "check every item in list is part of expected list in any order"() {
        when:
        List<Integer> result = [1, 1, 10, 2, 2, 20]

        then:
        result.every { i -> i in [20, 10, 2, 1]}
    }
}

Written with Spock 2.3-groovy-4.0.

Original post written on March 24, 2023

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(SampleSpecification.g\
roovy: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 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 ${range}")
            }
        ] 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(SampleSpecificatio\
n.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 post written on May 14, 2013

Providing Data

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 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 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 post written on June 16, 2014

Reuse Variables In Data Providers

Writing a parameterized specification in Spock is easy. We need to add the where: block and use data providers to specify different values. For each set of values from the data providers our specifications is run, so we can test for example very effectively multiple input arguments for a method and the expected outcome. A data provider can be anything that implements the Iterable interface. Spock also adds support for a data table. In the data table we define columns for each variable and in the rows values for each variable. Since Spock 1.1 we can reuse the value of the variables inside the data provider or data table. The value of the variable can only be reused in variables that are defined after the variable we want to reuse is defined.

In the following example we have two feature methods, one uses a data provider and one a data table. The variable sentence is defined after the variable search, so we can use the search variable value in the definition of the sentence variable.

package mrhaki

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

class CountOccurrencesSpec extends Specification {

    @Unroll('#sentence should have #count occurrences of #search (using data table)')
    void 'count occurrences of text using data table'() {
        expect:
        sentence.count(search) == count

        where:
        search  | sentence                                                  || count
        'ABC'   | "A simple $search"                                        || 1
        'Spock' | "Don't confuse $search framework, with the other $search" || 2
    }

    @Unroll('#sentence should have #count occurrences of #search (using data provider)')
    void 'count occurrences of text using data provider'() {
        expect:
        sentence.count(search) == count

        where:
        search << ['ABC', 'Spock']
        sentence << ["A simple $search", "Don't confuse $search framework, with the other $search"]
        count << [1, 2]
    }
}

When we run the specification the feature methods will pass and in we see in the @Unroll descriptions that the sentence variable uses the value of search:

Written with Spock 1.1-groovy-2.4.

Original post written on October 2, 2017

Using Mocks And stubs

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 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 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 post written on September 16, 2016

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 post written on September 24, 2013

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 method_\
closure2(SampleSpecification.groovy:25)
...

Code written with Spock 0.7-groovy-2.0

Original post written on May 17, 2013

Use Stub or Mock For Spring Component Using @SpringBean

When we write tests or specifications using Spock for our Spring Boot application, we might want to replace some Spring components with a stub or mock version. With the stub or mock version we can write expected outcomes and behaviour in our specifications. Since Spock 1.2 and the Spock Spring extension we can use the @SpringBean annotation to replace a Spring component with a stub or mock version. (This is quite similar as the @MockBean for Mockito mocks that is supported by Spring Boot). We only have to declare a variable in our specification of the type of the Spring component we want to replace. We directly use the Stub() or Mock() methods to create the stub or mock version when we define the variable. From now on we can describe expected output values or behaviour just like any Spock stub or mock implementation.

To use the @SpringBean annotation we must add a dependency on spock-spring module to our build system. For example if we use Gradle we use the following configuration:

...
dependencies {
    ...
    testImplementation("org.spockframework:spock-spring:1.3-groovy-2.5")
    ...
}
...

Let's write a very simple Spring Boot application and use the @SpringBean annotation to create a stubbed component. First we write a simple interface with a method that accepts an argument of type String and return a new String value:

package mrhaki.spock;

public interface MessageComponent {
    String hello(final String name);
}

Next we use this interface in a Spring REST controller where we use constructor dependency injection to inject the correct implementation of the MessageComponent interface into the controller:

package mrhaki.spock;

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MessageController {

    private final MessageComponent messageComponent;

    public MessageController(final MessageComponent messageComponent) {
        this.messageComponent = messageComponent;
    }

    @GetMapping(path = "/message", produces = MediaType.TEXT_PLAIN_VALUE)
    public String message(@RequestParam final String name) {
        return messageComponent.hello(name);
    }

}

To test the controller we write a new Spock specification. We use Spring's MockMvc support to test our controller, but the most important part in the specification is the declaration of the variable messageComponent with the annotation @SpringBean. Inside the method where we invoke /message?name=mrhaki we use the stub to declare our expected output:

package mrhaki.spock

import org.spockframework.spring.SpringBean
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
import org.springframework.test.web.servlet.MockMvc
import spock.lang.Specification

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get

@WebMvcTest(MessageController)
class MessageControllerSpec extends Specification {

    @Autowired
    private MockMvc mockMvc

    /**
     * Instead of the real MessageComponent implementation
     * in the application context we want to use our own
     * Spock Stub implementation to have control over the
     * output of the message method.
     */
    @SpringBean
    private MessageComponent messageComponent = Stub()

    void "GET /message?name=mrhaki should return result of MessageComponent using mrhaki as argument"(\
) {
        given: 'Stub returns value if invoked with argument "mrhaki"'
        messageComponent.hello("mrhaki") >> "Hi mrhaki"

        when: 'Get response for /message?name=mrhaki'
        final response = mockMvc.perform(get("/message").param("name", "mrhaki"))
                                .andReturn()
                                .getResponse()

        then:
        response.contentAsString == "Hi mrhaki"
    }
}

Written with Spock 1.3-groovy-2.5 and Spring Boot 2.1.8.RELEASE.

Original post written on September 10, 2019

Testing Asynchronous Code

Testing Asynchronous Code With DataVariable(s)

Testing asynchronous code needs some special treatment. With synchronous code we get results from invoking method directly and in our tests or specifications we can easily assert the value. But when we don’t know when the results will be available after calling a method we need to wait for the results. So in our specification we actually block until the results from asynchronous code are available. One of the options Spock provides us to block our testing code and wait for the code to be finished is using the classes DataVariable and DataVariables. When we create a variable of type DataVariable we can set and get one value result. The get method will block until the value is available and we can write assertions on the value as we now know it is available. The set method is used to assign a value to the BlockingVariable, for example we can do this in a callback when the asynchronous method support a callback parameter.

The BlockingVariable can only hold one value, with the other class BlockingVariables we can store multiple values. The class acts like a Map where we create a key with a value for storing the results from asynchronous calls. Each call to get the value for a given key will block until the result is available and ready to assert.

The following example code is a Java class with two methods, findTemperature and findTemperatures, that make asynchronous calls. The implementation of the methods use a so-called callback parameter that is used to set the results from invoking a service to get the temperature for a city:

package mrhaki;

import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.function.Consumer;

class Async {

    private final ExecutorService executorService;
    private final WeatherService weatherService;

    Async(ExecutorService executorService, WeatherService weatherService) {
        this.executorService = executorService;
        this.weatherService = weatherService;
    }

    // Find temperature for a city using WeatherService and
    // assign result using callback argument.
    void findTemperature(String city, Consumer<Result> callback) {
        // Here we do an asynchronous call using ExecutorService and
        // a Runnable lambda.
        // We're assigning the result of calling WeatherService using
        // the callback argument.
        executorService.submit(() -> {
            int temperature = weatherService.getTemperature(city);
            var result = new Result(city, temperature);
            callback.accept(result);
        });
    }

    // Find temperature for multiple cities using WeatherService and
    // assign result using callback argument.
    void findTemperatures(List<String> cities, Consumer<Result> callback) {
        cities.forEach(city -> findTemperature(city, callback));
    }

    record Result(String city, int temperature) {
    }

    interface WeatherService {
        int getTemperature(String city);
    }
}

To test our Java class we write the following specification where we use both DataVariable and DataVariables to wait for the asynchronous methods to be finished and we can assert on the resulting values:

package mrhaki

import spock.lang.Specification
import spock.lang.Subject
import spock.util.concurrent.BlockingVariable
import spock.util.concurrent.BlockingVariables

import java.util.concurrent.Executors

class AsyncSpec extends Specification {

    // Provide a stub for the WeatherService interface.
    // Return 21 on the first call and 18 on subsequent calls.
    private Async.WeatherService weatherService = Stub() {
        getTemperature(_ as String) >>> [21, 18]
    }

    // We want to test the class Async
    @Subject
    private Async async = new Async(Executors.newFixedThreadPool(2), weatherService)

    void "findTemperature should return expected temperature"() {
        given:
        // We define a BlockingVariable to store the result in the callback,
        // so we can wait for the value in the then: block and
        // asssert the value when it becomes available.
        def result = new BlockingVariable<Async.Result>()

        when:
        // We invoke the async method and in the callback use
        // our BlockingVariable to set the result.
        async.findTemperature("Tilburg") { Async.Result temp ->
            // Set the result to the BlockingVariable.
            result.set(temp)
        }

        then:
        // Now we wait until the result is available with the
        // blocking call get().
        // Default waiting time is 1 second. We can change that
        // by providing the number of seconds as argument
        // to the BlockingVariable constructor.
        // E.g. new BlockingVariable<Long>(3) to wait for 3 seconds.
        result.get() == new Async.Result("Tilburg", 21)
    }

    void "findTemperatures should return expected temperatures"() {
        given:
        // With type BlockingVariables we can wait for multiple values.
        // Each value must be assigned to a unique key.
        def result = new BlockingVariables(5)

        when:
        async.findTemperatures(["Tilburg", "Amsterdam"]) { Async.Result temp ->
            // Set the result with a key to the BlockingVariables result variable.
            // We can story multiple results in one BlockingVariables.
            result[temp.city()] = temp.temperature()
        }

        then:
        // We wait for the results key by key.
        // We cannot rely that the result are available in the
        // same order as the passed input arguments Tilburg and Amsterdam
        // as the call will be asynchronous.
        // But using BlockingVariables we dont' have to care,
        // we simply request the value for a key and the code will
        // block until it is available.
        result["Amsterdam"] == 18
        result["Tilburg"] == 21
    }
}

Written with Spock 2.3-groovy-4.0.

Original post written on April 10, 2023

Testing Asynchronous Code With PollingConditions

In a previous blog post we learned how to use DataVariable and DataVariables to test asynchronous code. Spock also provides PollingConditions as a way to test asynchronous code. The PollingConditions class has the methods eventually and within that accept a closure where we can write our assertions on the results of the asynchronous code execution. Spock will try to evaluate conditions in the closure until they are true. By default the eventually method will retry for 1 second with a delay of 0.1 second between each retry. We can change this by setting the properties timeout, delay, initialDelay and factor of the PollingConditions class. For example to define the maximum retry period of 5 seconds and change the delay between retries to 0.5 seconds we create the following instance: new PollingConditions(timeout: 5, initialDelay: 0.5).\ Instead of changing the PollingConditions properties for extending the timeout we can also use the method within and specify the timeout in seconds as the first argument. If the conditions can be evaluated correctly before the timeout has expired then the feature method of our specification will also finish earlier. The timeout is only the maximum time we want our feature method to run.

In the following example Java class we have the methods findTemperature and findTemperatures that will try to get the temperature for a given city on a new thread. The method getTemperature will return the result. The result can be null as long as the call to the WeatherService is not yet finished.

package mrhaki;

import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;

class AsyncWeather {

    private final ExecutorService executorService;
    private final WeatherService weatherService;

    private final Map<String, Integer> results = new ConcurrentHashMap<>();

    AsyncWeather(ExecutorService executorService, WeatherService weatherService) {
        this.executorService = executorService;
        this.weatherService = weatherService;
    }

    // Invoke the WeatherService in a new thread and store result in results.
    void findTemperature(String city) {
        executorService.submit(() -> results.put(city, weatherService.getTemperature(city)));
    }

    // Invoke the WeatherService in a new thread for each city and store result in results.
    void findTemperatures(String... cities) {
        Arrays.stream(cities)
              .parallel()
              .forEach(this::findTemperature);
    }

    // Get the temperature. Value can be null when the WeatherService call is not finished yet.
    int getTemperature(String city) {
        return results.get(city);
    }

    interface WeatherService {
        int getTemperature(String city);
    }
}

To test the class we write the following specification using PollingConditions:

package mrhaki

import spock.lang.Specification
import spock.lang.Subject
import spock.util.concurrent.PollingConditions

import java.util.concurrent.Executors

class AsyncPollingSpec extends Specification {

    // Provide a stub for the WeatherService interface.
    // Return 21 when city is Tilburg and 18 for other cities.
    private AsyncWeather.WeatherService weatherService = Stub() {
        getTemperature(_ as String) >> { args ->
            if ("Tilburg" == args[0]) 21 else 18
        }
    }

    // We want to test the class AsyncWeather
    @Subject
    private AsyncWeather async = new AsyncWeather(Executors.newFixedThreadPool(2), weatherService)

    void "findTemperature and getTemperature should return expected temperature"() {
        when:
        // We invoke the async method.
        async.findTemperature("Tilburg")

        then:
        // Now we wait until the results are set.
        // By default we wait for at  most 1 second,
        // but we can configure some extra properties like
        // timeout, delay, initial delay and factor to increase delays.
        // E.g. new PollingConditions(timeout: 5, initialDelay: 0.5, delay: 0.5)
        new PollingConditions().eventually {
            // Although we are in a then block, we must
            // use the assert keyword in our eventually
            // Closure code.
            assert async.getTemperature("Tilburg") == 21
        }
    }

    void "findTemperatures and getTemperature shoud return expected temperatures"() {
        when:
        // We invoke the async method.
        async.findTemperatures("Tilburg", "Amsterdam")

        then:
        // Instead of using eventually we can use within
        // with a given timeout we want the conditions to
        // be available for assertions.
        new PollingConditions().within(3) {
            // Although we are in a then block, we must
            // use the assert keyword in our within
            // Closure code.
            assert async.getTemperature("Amsterdam") == 18
            assert async.getTemperature("Tilburg") == 21
        }
    }
}

Written with Spock 2.4-groovy-4.0.

Original post written on April 10, 2023

Running Spock

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 post written on June 20, 2014

Ignoring Other Feature Methods Using @IgnoreRest

To ignore feature methods in our Spock specification we can use the annotation @Ignore. Any feature method or specification with this annotation is not invoked when we run a specification. With the annotation @IgnoreRest we indicate that feature methods that do not have this annotation must be ignored. So any method with the annotation is invoked, but the ones without aren't. This annotation can only be applied to methods and not to a specification class.

In the next example we have a specification with two feature methods that will be executed and one that is ignored:

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

class SampleSpec extends Specification {

    @Subject
    private final underTest = new Sample()

    @IgnoreRest
    void 'run this spec'() {
        expect:
        underTest.message('Asciidoctor') == 'Asciidoctor is awesome.'
    }
    
    @IgnoreRest
    void 'run this spec also'() {
        expect:
        underTest.message('Groovy') == 'Groovy is awesome.'
    }

    void 'ignore this spec'() {
        expect:
        underTest.message('Word') == 'Word is awesome'
    }
    
}

class Sample {
    String message(String tool) {
        println "Getting message for $tool"
        "$tool is awesome."
    }
}

We can run this specification directly from the command line:

$ groovy SampleSpec.groovy
Getting message for Asciidoctor
Getting message for Groovy
JUnit 4 Runner, Tests: 2, Failures: 0, Time: 54
$

Written with Spock 1.0 and Groovy 2.4.10.

Original post written on April 10, 2017

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 post written on September 4, 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 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 post written on August 28, 2015

Miscellaneous

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 post written on October 13, 2014

Indicate Specification As Pending Feature

Sometimes we are working on a new feature in our code and we want to write a specification for it without yet really implementing the feature. To indicate we know the specification will fail while we are implementing the feature we can add the @PendingFeature annotation to our specification method. With this annotation Spock will still execute the test, but will set the status to ignored if the test fails. But if the test passes the status is set to failed. So when we have finished the feature we need to remove the annotation and Spock will kindly remind us to do so this way.

In the following example specification we use the @PendingFeature annotation:

package sample

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

class SampleSpec extends Specification {

    @Subject
    private final converter = new Converter()

    @PendingFeature
    void 'new feature to make String upper case'() {
        given:
        def value = 'Spock is awesome'

        expect: // This will fail as expected
        converter.upper(value) == 'SPOCK IS AWESOME'
    }

}

class Converter {
    String upper(String value) {
        value
    }
}

When we run our test in for example Gradle we get the following result:

Now let's implement the upper method:

package sample

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

class SampleSpec extends Specification {

    @Subject
    private final converter = new Converter()

    @PendingFeature
    void 'new feature to make String upper case'() {
        given:
        def value = 'Spock is awesome'

        expect: // This will fail no more
        converter.upper(value) == 'SPOCK IS AWESOME'
    }

}

class Converter {
    String upper(String value) {
        value.toUpperCase()
    }
}

We run the test again and now we get a failing result although our implementation of the upper method is correct:

So this tells us the @PendingFeature is no longer needed. We can remove it and the specification will pass correctly.

Written with Spock 1.1.

Original post written on June 2, 2017

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 post written on August 22, 2013

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 post written on September 1, 2015

Creating Temporary Files And Directories With FileSystemFixture

If we write specification where we need to use files and directories we can use the @TempDir annotation on a File or Path instance variable. By using this annotation we make sure the file is created in the directory defined by the Java system property java.io.tmpdir. We could overwrite the temporary root directory using Spock configuration if we want, but the default should be okay for most situations. The @TempDir annotation can actually be used on any class that has a constructor with a File or Path argument. Since Spock 2.2 we can use the FileSystemFixture class provided by Spock. With this class we have a nice DSL to create directory structures and files in a simple matter. We can use the Groovy extensions to File and Path to also immediately create contents for the files. If we want to use the extensions to Path we must make sure we include org.apache.groovy:groovy-nio as dependency to our test runtime classpath. The FileSystemFixture class also has the method copyFromClasspath that we can use to copy files and their content directory into our newly created directory structure.

In the following example specification we use FileSystemFixture to define a new directory structure in a temporary directory, but also in our project directory:

package mrhaki

import spock.lang.Specification
import spock.lang.Subject
import spock.lang.TempDir
import spock.util.io.FileSystemFixture

import java.nio.file.Path
import java.nio.file.Paths

class FileFixturesSpec extends Specification {

    /**
     * Class we want to test. The class has a method
     * File renderDoc(File input, File outputDir) that takes
     * an input file and stores a rendered file in the given
     * output directory.
     */
    @Subject
    private DocumentBuilder documentBuilder = new DocumentBuilder()

    /**
     * With the TempDir annotation we make sure our directories and
     * files created with FileSystemFixture are deleted after
     * each feature method run.
     */
    @TempDir
    private FileSystemFixture fileSystemFixture

    void "convert document"() {
        given:
        // Create a new directory structure in the temporary directory
        // <root>
        //  +-- src
        //  |    +-- docs
        //  |         +-- input.adoc
        //  |         +-- convert.adoc
        //  +-- output
        fileSystemFixture.create {
            dir("src") {
                dir("docs") {
                    // file(String) returns a Path and with
                    // groovy-nio module on the classpath we can use
                    // extensions to add text to file. E.g. via the text property.
                    file("input.adoc").text = '''\
                    = Sample

                    Welcome to *AsciidoctorJ*.
                    '''.stripIndent()

                    // Copy file from classpath (src/test/resources)
                    // and rename it at the same time.
                    // Without rename it would be
                    // copyFromClasspath("/samples/sample.adoc")
                    copyFromClasspath("/samples/sample.adoc", "convert.adoc")
                }
            }
            dir("output")
        }

        and:
        // Using resolve we get the actual Path to the file
        Path inputDoc = fileSystemFixture.resolve("src/docs/input.adoc")
        Path convertDoc = fileSystemFixture.resolve("src/docs/convert.adoc")

        // We can also use Paths to resolve the actual Path.
        Path outputDir = fileSystemFixture.resolve(Paths.get("output"))

        when:
        File resultDoc = documentBuilder.renderDoc(inputDoc.toFile(), outputDir.toFile())

        then:
        resultDoc.text =~ "<p>Welcome to <strong>AsciidoctorJ</strong>.</p>"

        when:
        File resultConvert = documentBuilder.renderDoc(convertDoc.toFile(), outputDir.toFile())

        then:
        resultConvert.text =~ "<p>Testing <strong>AsciidoctorJ</strong> with Spock 🚀</p>"
    }

    void "convert document from non-temporary dir"() {
        given:
        // Create FileSystemFixture in our project build directory.
        FileSystemFixture fileSystemFixture = new FileSystemFixture(Paths.get("build"))
        fileSystemFixture.create {
            dir("test-docs") {
                dir("src") {
                    dir("docs") {
                        copyFromClasspath("/samples/sample.adoc")
                    }
                }
                dir("output")
            }
        }

        and:
        Path convertDoc = fileSystemFixture.resolve("test-docs/src/docs/sample.adoc")
        Path outputDir = fileSystemFixture.resolve(Paths.get("test-docs/output"))

        when:
        File resultDoc = documentBuilder.renderDoc(convertDoc.toFile(), outputDir.toFile())

        then:
        resultDoc.text =~ "<p>Testing <strong>AsciidoctorJ</strong> with Spock 🚀</p>"

        cleanup:
        // We can delete the test-docs directory ourselves.
        fileSystemFixture.resolve("test-docs").deleteDir()
    }
}

In order to use the Groovy extensions for java.nio.Path we must add the groovy-nio module to the test classpath. For example we can do this if we use Gradle by using the JVM TestSuite plugin extension:

plugins {
    java
    groovy
}

...

repositories {
    mavenCentral()
}

testing {
    suites {
        val test by getting(JvmTestSuite::class) {
            // Define we want to use Spock.
            useSpock("2.3-groovy-4.0")
            dependencies {
                // Add groovy-nio module.
                implementation("org.apache.groovy:groovy-nio")
            }
        }
    }
}

Written with Spock 2.3-groovy-4.0 and Gradle 8.0.2.

Original post written on March 30, 2023

Adjusting Time With MutableClock

Testing classes that work with date calculations based on the current date and time (now) can be difficult. First of all we must make sure our class under test accepts a java.time.Clock instance. This allows us to provide a specific Clock instance in our tests where we can define for example a fixed value, so our tests don't break when the actual date and time changes. But this can still not be enough for classes that will behave different based on the value returned for now. The Clock instances in Java are immutable, so it is not possible to change the date or time for a Clock instance.

In Spock 2.0 we can use the new MutableClock class in our specifications to have a Clock that can be used to go forward or backward in time on the same Clock instance. We can create a MutableClock and pass it to the class under test. We can test the class with the initial date and time of the Clock object, then change the date and time for the clock and test the class again without having to create a new instance of the class under test. This is handy in situations like a queue implementation, where a message delivery date could be used to see if messages need to be delivered or not. By changing the date and time of the clock that is passed to the queue implementation we can write specifications that can check the functionality of the queue instance.

The MutableClock class has some useful methods to change the time. We can for example use the instant property to assign a new Instant. Or we can add or subtract a duration from the initial date and time using the + and - operators. We can specify the temporal amount that must be applied when we use the ++ or -- operators. Finally, we can use the adjust method with a single argument closure to use a TemporalAdjuster to change the date or time. This last method is useful if we want to specify a date adjustment that is using months and years.

In the following example Java code we have the class WesternUnion that accepts letters with a delivery date and message. The letter is stored and when the deliver method is we remove the letter from our class if the delivery date is after the current date and time.

package mrhaki;

import java.time.Clock;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;

/**
 * Class to mimic a letter delivery service, 
 * that should deliver letters after the letter
 * delivery data has passed.
 */
public class WesternUnion {
    private final Clock clock;
    private final List<Letter> letters = new ArrayList<>();

    /**
     * Default constructor that uses a default Clock with UTC timezone.
     */
    public WesternUnion() {
        this(Clock.systemUTC());
    }

    /**
     * Constructor that accepts a clock, very useful for testing.
     * 
     * @param clock Clock to be used in this class for date calculations.
     */
    WesternUnion(final Clock clock) {
        this.clock = clock;
    }

    /**
     * Store accepted letter.
     * 
     * @param deliveryDate Date the letter should be deliverd.
     * @param message Message for the letter.
     */
    public int acceptLetter(Instant deliveryDate, String message) {
        final Letter letter = new Letter(deliveryDate, message);
        letters.add(letter);
        return letters.size();
    }

    /**
     * "Deliver" letters where the delivery date has passed.
     */
    public int deliver() {
        Instant now = Instant.now(clock);
        letters.removeIf(letter -> letter.getDeliveryDate().isBefore(now));
        return letters.size();
    }

    /**
     * Simple record for a "letter" which a delivery date and message.
     */
    private record Letter(Instant deliveryDate, String message) {
        private Instant getDeliveryDate() {
            return deliveryDate;
        }
    }
}

In order to test this class we want pass a Clock instance where we can mutate the clock, so we can test if the deliver method works if we invoke it multiple times. In the next specification we test this with different usages of MutableClock. Each specification method uses the MutableClock in a different way to test the WesternUnion class:

package mrhaki

import spock.lang.Specification
import spock.lang.Subject
import spock.util.time.MutableClock

import java.time.Duration
import java.time.Instant
import java.time.Period
import java.time.ZoneId
import java.time.ZonedDateTime

class WesternUnionSpec extends Specification {

    // Default time zone used for letter dates.
    private static final ZoneId TZ_HILL_VALLEY = ZoneId.of("America/Los_Angeles")
    
    // Constants used for letter to be send.
    private static final Instant DELIVERY_DATE = 
        ZonedDateTime
            .of(1955, 11, 12, 0, 0, 0, 0, TZ_HILL_VALLEY)
            .toInstant()
    private static final String MESSAGE = 
      'Dear Marty, ... -Your friend in time, "Doc" Emmett L. Brown'

    @Subject
    private WesternUnion postOffice

    void "deliver message after delivery date"() {
        given: "Set mutable clock instant to Sept. 1 1885"
        def clock = new MutableClock(
          ZonedDateTime.of(1885, 9, 1, 0, 0, 0, 0, TZ_HILL_VALLEY))

        and:
        postOffice = new WesternUnion(clock)

        expect:
        postOffice.acceptLetter(DELIVERY_DATE, MESSAGE) == 1

        when:
        int numberOfLetters = postOffice.deliver()

        then: "Delivery date has not passed so 1 letter"
        numberOfLetters  == 1

        when: "Move to delivery date of letter + 1 day and try to deliver"
        // We can change the clock's Instant property directly to 
        // change the date.
        clock.instant = 
            ZonedDateTime
                .of(1955, 11, 13, 0, 0, 0, 0, TZ_HILL_VALLEY)
                .toInstant()
        int newNumberOfLetters = postOffice.deliver()

        then: "Delivery date has passed now so 0 letters left"
        newNumberOfLetters == 0
    }
    
    void "deliver message after adjusting MutableClock using adjust"() {
        given: "Set mutable clock instant to Sept. 1 1885"
        def clock = new MutableClock(
            ZonedDateTime.of(1885, 9, 1, 0, 0, 0, 0, TZ_HILL_VALLEY))
        
        and:
        postOffice = new WesternUnion(clock)

        expect:
        postOffice.acceptLetter(DELIVERY_DATE, MESSAGE) == 1

        when:
        int numberOfLetters = postOffice.deliver()
        
        then: "Delivery date has not passed so 1 letter"
        numberOfLetters  == 1

        when: "Move clock forward 70 years, 2 months and 12 days and try to deliver"
        // To move the clock forward or backward by month or years we need
        // the adjust method. The plus/minus/next/previous methods are applied
        // to the Instant property of the MutableClock and with Instant
        // we can not use months or years.
        clock.adjust {t -> t + (Period.of(70, 2, 12)) }
        int newNumberOfLetters = postOffice.deliver()
        
        then: "Delivery date has passed now so 0 letters left"
        newNumberOfLetters == 0
    }

    void "deliver message after adding amount to MutableClock"() {
        given: "Set mutable clock instant to Oct. 26 1955"
        def clock = new MutableClock(
            ZonedDateTime.of(1955, 10, 26, 0, 0, 0, 0, TZ_HILL_VALLEY))

        and:
        postOffice = new WesternUnion(clock)

        expect:
        postOffice.acceptLetter(DELIVERY_DATE, MESSAGE) == 1

        when:
        int numberOfLetters = postOffice.deliver()

        then: "Delivery date has not passed so 1 letter"
        numberOfLetters  == 1

        and: "Move clock forward by given amount (18 days) and try to deliver"
        // The +/- operators are mapped to plus/minus methods. 
        // Amount cannot be months or years, then we need the adjust method.
        clock + Duration.ofDays(18)

        when: "Try to deliver now"
        int newNumberOfLetters = postOffice.deliver()

        then: "Delivery date has passed now so 0 letters left"
        newNumberOfLetters == 0
    }
    
    void "deliver message with fixed change amount"() {
        given: "Set mutable clock instant to Oct. 26 1955"
        def defaultTime = 
            ZonedDateTime.of(1955, 10, 26, 0, 0, 0, 0, TZ_HILL_VALLEY)
        // We can set the changeAmount property of MutableClock 
        // in the constructor or by setting the changeAmount property. 
        // Now when we invoke next/previous (++/--)
        // the clock moves by the specified amount.
        def clock = 
            new MutableClock(
                defaultTime.toInstant(), 
                defaultTime.zone, 
                Duration.ofDays(18))

        and:
        postOffice = new WesternUnion(clock)

        expect:
        postOffice.acceptLetter(DELIVERY_DATE, MESSAGE) == 1

        when:
        int numberOfLetters = postOffice.deliver()

        then: "Delivery date has not passed so 1 letter"
        numberOfLetters  == 1

        and: "Move clock forward by given amount (18 days) and try to deliver"
        // The ++/-- operators are mapped to next/previous. 
        // Amount cannot be months or years, then we need the adjust method.
        clock++

        when: "Try to deliver now"
        int newNumberOfLetters = postOffice.deliver()

        then: "Delivery date has passed now so 0 letters left"
        newNumberOfLetters == 0
    }
}

Written with Spock 2.0.

Original post written on October 26, 2021

Set Timeout On Specification Methods

When we write a feature method in our Spock specification to test our class we might run into long running methods that are invoked. We can specify a maximum time we want to wait for a method. If the time spent by the method is more than the maximum time our feature method must fail. Spock has the @Timeout annotation to define this. We can apply the annotation to our specification or to feature methods in the specification. We specify the timeout value as argument for the @Timeout annotation. Seconds are the default time unit that is used. If we want to specify a different time unit we can use the annotation argument unit and use constants from java.util.concurrent.TimeUnit to set a value.

In the following example specification we set a general timeout of 1 second for the whole specification. For two methods we override this default timeout with their own value and unit:

package mrhaki.spock

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

import static java.util.concurrent.TimeUnit.MILLISECONDS

// Set a timeout for all feature methods.
// If a feature method doesn't return in 1 second
// the method fails.
@Timeout(1)
class SampleSpec extends Specification {

    @Subject
    private final Sample sample = new Sample()

    // Check that method will return within 1 second.
    void 'timeout will not happen'() {
        expect:
        sample.run(500) == 'Awake after 500 ms.'
    }

    // Method will fail, because it doesn't return in 1 second.
    void 'method under test should return in 1 second'() {
        expect:
        sample.run(1500) == 'Awake after 1500 ms.'
    }

    // We can change the timeout value and 
    // the unit. The unit type is 
    // java.util.concurrent.TimeUnit.
    @Timeout(value = 200, unit = MILLISECONDS)
    void 'method under test should return in 200 ms'() {
        expect:
        sample.run(100) == 'Awake after 100 ms.'
    }

    // Method will fail.
    @Timeout(value = 100, unit = MILLISECONDS)
    void 'method under test should return in 100 ms'() {
        expect:
        sample.run(200) == 'Awake after 200 ms.'
    }

}

// Simple class for testing.
class Sample {
    /**
     * Run method and sleep for specified timeout value.
     *
     * @param timeout Sleep number of milliseconds specified
     *                by the timeout argument.
     * @return String value with simple message.
     */
    String run(final Long timeout) {
        sleep(timeout)
        "Awake after $timeout ms."
    }
}

Written with Spock 1.0-groovy-2.4.

Original post written on April 11, 2017

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 post written on September 3, 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 post written on September 4, 2015