Blog JVM Stuff.

Spock - Mocking and Stubbing

Spock [0] is a testing and specification library for Groovy and Java projects. Just recently I figured that quite a large number of Grails and Groovy developers I know are not aware of another really cool Spock feature: Mocking and Stubbing.

Mocking with Spock

A mock is an object of a certain type but without any behavior. Instead, the expected behavior is specified by the developer writing the specification. There is a large number of mocking libraries in the Java space, in my past Java projects I used EasyMock [1] quite frequently. The Spock developers made the decision to write their own mocking functionality being tightly integrated into the Spock library and using some of the Groovy language features that make code easier to read and maintain. Enough said, let's see mocking in action. We have a class ItemProcessor. The ItemProcess processes and saves items. For saving the items, it has a dependency on another class: ItemRepository.
 

class ItemProcessor {
  void process(List<Long> itemIds) { /* ... */ }
}

class ItemRepository {
  void save(List<Item> items) { /* ... */ }
}
 
Now we have to write a specification for our ItemProcessor that ensures the items are saved via the ItemRepository. The Spock specification looks like this:
 
class ItemProcessorSpec extends Specification {

  ItemProcessor processor = new ItemProcessor()

  def "processed items have to be saved"() { 

    when: "the processor is given a bunch of item IDs"
      processor.process([42l, 1l, 3l])

    then: "the item instances must be saved"
      // TBC

   }
}
 
Mocks created by Spock are lenient by default. In other words: calls on mock methods which haven't been mocked return default values from their return types instead of throwing an error. The way to create mocks in Spock is by using the Mock() method. The method does not come with any required parameters, although some variations of Mock() are available. In order to have the generic type information of the Mock return type, we will use the Mock(Class) interface for our example. Please note that ItemRepository is a concrete class, Spock allows mocking for interfaces and concrete classes, let it be Groovy or Java (!) classes.
 
class ItemProcessorSpec extends Specification {

  ItemProcessor processor
  ItemRepository repository

  def setup() {
    processor = new ItemProcessor()
    repository = Mock(ItemRepository)
  }
  // ...

}
 
Now comes the really cool part. We have to specify how many times we expect our save method from the repository to be called. This can be done with using a special Spock mocking DSL:
 

def "processed items have to be saved"() { 

  when: "the processor is given a bunch of item IDs"
    processor.process([42l, 1l, 3l])

  then: "the item instances must be saved"
    1 * repository.save(_)
}
 
As can be seen in the code example above, the DSL expressions holds the cardinality (1 *), the target constraint (repository), the method constraint (save) and an argument constraint (_). The code uses the underscore as argument constraint. The underscore has a special semantic, it acts as "any" operator and can also be used for the other constraints. The mock spec above can be read as: "execute repository.save a single time no matter what in put arguments are given". But we could use a true argument constraint either:
 

def "processed items have to be saved"() { 

  when: "the processor is given a bunch of item IDs"
    processor.process([42l, 1l, 3l])

  then: "the item instances must be saved"
    1 * repository.save([new Item(id: 42l), new Item(id: 1l), new Item(id: 3l)])
}
 
This restricts the mock to exactly that list of Item instances. The Spock documentation [2] shows more examples for valid mock expressions:
 
1 * subscriber.receive("hello")     // an argument that is equal to the String "hello"

1 * subscriber.receive(!"hello")    // an argument that is unequal to the String "hello"

1 * subscriber.receive()            // the empty argument list (would never match in our example)

1 * subscriber.receive(_)           // any single argument (including null)

1 * subscriber.receive(*_)          // any argument list (including the empty argument list)

1 * subscriber.receive(!null)       // any non-null argument

1 * subscriber.receive(_ as String) // any non-null argument that is-a String

1 * subscriber.receive({ it.size() > 3 }) // an argument that satisfies the given predicate

                                          // (here: message length is greater than 3)

 

Stubbing with Spock

Now we want to do some stubbing. For this case, let's assume the save method in the ItemRepository is rewritten to return the newly saved Items. We have to change our test-case to return a list of saved Item instances.
 
def "processed items have to be saved"() { 

  when: "the processor is given a bunch of item IDs"
    processor.process([42l, 1l, 3l])

  then: "the item instances must be saved"
    1 * repository.save([new Item(id: 42l), new Item(id: 1l), new Item(id: 3l)]) >> 
       [new Item(id: 42l), new Item(id: 1l), new Item(id: 3l)]
}
 
As you can see above, the right-shift operator is used to return a fixed value. If we would have used to underscore we could use the triple-right-shift operator for subsequent return values:
 
def "processed items have to be saved"() { 

  when: "the processor is given a bunch of item IDs"
    processor.process([42l, 1l, 3l])

  then: "the item instances must be saved"
    1 * repository.save(_) >>> [[new Item(id: 42l), new Item(id: 1l), new Item(id: 3l)], []]
}
 
We could also use the "computed" return value feature to deduce the return value from the arguments to the method call which are available in the args variable:
 
def "processed items have to be saved"() { 

  when: "the processor is given a bunch of item IDs"
    processor.process([42l, 1l, 3l])

  then: "the item instances must be saved"
    1 * repository.save(_) >> { args -> args[0] }
}
 

Spying with Spock

Spies stub specific methods from otherwise concrete classes leaving the original methods as-is. In other words, that non-stubbed methods are delegated to a real object the stubbed methods overshadow the real methods. More on spies can be found in the Spock documentation [3].

Conclusion

This article should have given you a small pointer on what is possible with Spock's mocking and stubbing features. It is a really nice and mighty feature people new to Spock might not be aware of.

[0] Spock - The Enterprise Ready Testing Framework
[1] EasyMock - Java Mocking Library
[2] Spock - Interaction-Based Testing
[3] Spock Documentation - Other Kinds of Mock Objects