Spock Mock Cheatsheet

Summary of unit test mocking capabilites and syntax of Spock test framework.

Object Partners

The Spock testing framework includes powerful mocking capabilities that work well in unit tests. The Spock documentation is extensive, but I often find myself hunting for the syntax of the different mocking mechanisms in Spock. So I created this cheat sheet to help organize the syntax in one concise spot.

I also created a one-page PDF cheatsheet for handy access to this info.

Config for mocking classes

First, we’ll need to include libraries that Spock needs for mocking classes. Grails already defines these dependencies defined, but if you’re using Gradle you’ll need to add them to support mocking classes. Add cglib 2.2 or higher as a dependency if you want to mock classes, and objenesis 1.2 or higher if you want to mock final classes.

dependencies {
    compile 'org.codehaus.groovy:groovy-all:2.1.3'
    testCompile 'org.spockframework:spock-core:0.7-groovy-2.0'

    testCompile 'cglib:cglib-nodep:2.2'       // For mocking classes
    testCompile 'org.objenesis:objenesis:1.2' // For mocking final classes
}

Creating mocks

There are a couple different ways to create a mock class. The first is to set the type on when declaring the variable for the mock. Spock will then determine the class of the mock from the type of the variable.

UserController userController

UserService userService

def setup() {
    userService = Mock()

    userController = new UserController(
            userService: userService
    )
}

The second way is to use a ‘def’ in the variable definition and pass the class name to the Mock() call

def userService = Mock(UserService)

Matching method arguments in mock method calls

Now that we’ve created our mock and used it in the class we’re testing (UserController, in this case), let’s use the mock. Spock provides several different ways to define mock methods and when those mock method definitions will match calls in the code under test.

The most lenient type of argument matching in a mock method call is the underscore, which will match anything that is passed into it:

def 'wildcard-based method argument matching'() {
    given:
    User user = new User()

    when:
    userController.createUser("test@email.com", "John Doe")

    then:
    1 * userService.createUser(_, _) >> user
    1 * userService.sendWelcomeEmail(user)
}

A slightly more strict form of argument matching is to match on the classes of the mock method arguments:

    then:
    1 * userService.createUser(_ as String, _ as String) >> user
    1 * userService.sendWelcomeEmail(user)

The strictest form of matching that produces the most thorough tests is to match the exact method arguments:

def 'exact argument matching'() {
    given:
    User user = new User()

    String email = "test@email.com"
    String name = "John Doe"

    when:
    userController.createUser(email, name)

    then:
    1 * userService.createUser(email, name) >> user
    1 * userService.sendWelcomeEmail(user)
}

A substitute for exact argument matching that can come in handy when you don’t have access to the exact object in the test, but can match on properties of the object is the closure form of argument matching:

def 'closure-based argument matching'() {
    given:
    String email = "test@email.com"
    String name = "John Doe"

    when:
    userController.createUser(email, name)

    then:
    1 * userService.createUser(email, name) >> new User(email: email, name: name)
    1 * userService.sendWelcomeEmail({ User u -> u.email == email && u.name == name })
}

Verifying mock method call number and order

Spock provides a convenient way to verify the number of times a mock method is called. And in addition to verifying the mock method calls we specify, we can verify no other extra methods are called on our mock objects:

    then:
    1 * userService.createUser(email, name) >> user
    1 * userService.sendWelcomeEmail(user)
    0 * _

Spock also provides the ability to verify the order in which mock methods are called by specifying the order in multiple ‘then’ blocks:

def 'verify mock method call order - pass'() {
    given:
    User user = new User()

    String email = "test@email.com"
    String name = "John Doe"

    when:
    userController.createUser(email, name)

    then:
    1 * userService.createUser(email, name) >> user

    then:
    1 * userService.sendWelcomeEmail(user)
}

Defining mock method calls outside of test spec

There may be times where you want to re-use your mock method definitions across multiple test cases. This can be a handy way to reduce copy-paste in test code. You can easily move the mock method definitions into their own method, just be sure to wrap that method call in an ‘interaction’ closure.

def 'mock definition outside of test spec'() {
    given:
    String email = "test@email.com"
    String name = "John Doe"

    when:
    userController.createUser(email, name)

    then:
    interaction {
        userCreationMocks(email, name)
    }
}

private void userCreationMocks(String email, String name) {
    User user = new User()

    1 * userService.createUser(email, name) >> user
    1 * userService.sendWelcomeEmail(user)
}

Using method arguments in return value

There may be cases where we want to access the arguments passed into the mock method and use those arguments in the return value of the mock call. Spock provides a way to do this by using a closure with the same number and type of arguments as the mock method.

def 'use method arguments in return value'() {
    given:
    String email = "test@email.com"
    String name = "John Doe"

    when:
    userController.createUser(email, name)

    then:
    1 * userService.createUser(email, name) >> { String e, String n ->
        new User(email: e, name: n)
    }
    1 * userService.sendWelcomeEmail(_ as User)
}

Example code

I put sample tests illustrating these different types of Spock mock usage into Gradle project available on GitHub: https://github.com/craigatk/spock-mock-cheatsheet And the PDF cheatsheet is available as well.

Happy mocking!

Share this Post

Related Blog Posts

JVM

A Groovy Time with UPnP and WeMo

March 25th, 2014

How to control a WeMo device using Groovy

Brendon Anderson
JVM

GUM Recap - Enterprise Grails with Spring Batch

February 13th, 2014

Recap of John Engelmans presentation at the January 2014 Groovy Users of Minnesota (GUM) meeting on utilizing Spring Batch with Grails applications.

Object Partners
JVM

Memoization in Groovy

January 28th, 2014

The performance of expensive calculations in Groovy can be increased with the use of memoization.

Brendon Anderson

About the author