Written on
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) { /* ... */ }
}
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
}
}
class ItemProcessorSpec extends Specification {
ItemProcessor processor
ItemRepository repository
def setup() {
processor = new ItemProcessor()
repository = Mock(ItemRepository)
}
// ...
}
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(_)
}
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)])
}
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)]
}
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)], []]
}
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] }
}