Programming for fun and profit

Programming tutorials, problems, solutions. Always with code.

Spock Framework Mock and Closures

Spock Framework Mock‘s are very easy to use. When mixed with Groovy closures they become even more powerful and allow us to look inside passed parameters. Learn how to mix both!

Domain model

In the post Spock Framework Mock we’ve created basic Java classes as our domain model and a controller that we want to test. There you could also see how to define simple interactions with Spock Framework Mocks.

The model is simple and if you already know that just skip to the next section.

Spock test with Groovy closures

Now, let’s add the following test:

// an interface with two methods: exists(user), add(user)
def userService = Mock(UserService)

// a controller to test, that will use mock of the service:
def userController = new UserController(userService: userService)

def 'should add a new user'() {
    // The first call to "exists" will return "false",
    // all subsequent calls will return "true":
    userService.exists(_ as User) >>> [false, true]

    when: '1st call should add user'
    userController.addUser('Jon Snow')

    1 * userService.add(_ as User) >> {
        // This way we've got access to params in a closure:
        User user ->
        // Asserts are implicit only in "then" and "expect" blocks
        // so here we have to use it explicitly:
        assert == 'Jon Snow'

    when: '2nd call should do nothing, because user exists'
    userController.addUser('Ramsay Snow')

    0 * userService.add(_ as User)

Important things to note:

  1. when-then blocks can occur many times in Spock test – not only once.
  2. The expression >>> [items] means that each call to Mock‘s method will return subsequent item from the list, and the last one will be returned indefinitely.
  3. >> {…} in the first then-block means that closure (anonymous, executable block of code in braces) will be executed on the call to the Mock‘s method. It can return a value, which is not needed here.
  4. In closures assert must be explicitly stated.

Different actions with chained methods

In the above example we’ve called just one Groovy closure, which is the most common case. However, sometimes we want to test how our code behaves when the same mock method behaves differently in subsequent calls (for instance this can happen when calling an external system and we are implementing a retry mechanism).

// A Gateway to an external system that can fail sometimes:
def gateway = Mock(Gateway)

// My service must retry when gateway returns an error:
def service = new MyRobustService(gateway)

def 'should retry on error'() {
    // The first call will get hit by the exception,
    // the next one return "true": >> { throw new RuntimeException() } >> true

    def processed = service.process('Jon Snow')

    then: 'RuntimeException should be handled and retry applied'


Note how we mixed call to Groovy closure with simple stubbing (returning true here) of mocked method. Methods can be chained many times, which gives a lot of flexibility.

MyRobustService implementation is left as an exercise for the reader. :-)

What’s next

Next time we’re going to play with exceptions in Spock Framework tests.

Share with the World!