Skip to content

Yet another programming solutions log

Sample bits from programming for the future generations.

Technologies Technologies
  • Algorithms and Data Structures
  • Java Tutorials
  • JUnit Tutorial
  • MongoDB Tutorial
  • Quartz Scheduler Tutorial
  • Spock Framework Tutorial
  • Spring Framework
  • Bash Tutorial
  • Clojure Tutorial
  • Design Patterns
  • Developer’s Tools
  • Productivity
  • About
Expand Search Form

Spock spy and partial mocking

farenda 2015-12-14 3

Problem:

How to create Spock Spy and do partial mocking? In this post we’re going to show practical application of partial mocking using Spy. Let’s test!

Let’s pretend that the following interface is Camel Processor ;-)

package com.farenda.spock;

public interface Processor {
    void process(String exchange);
}

And the code below is our ProcessorFactory that creates our complex processors and we want to unit test only its create(Strategy) method. The problem is that it calls other factory methods that do some complex setup, which we don’t want to test here.

package com.farenda.spock;

import java.util.List;

public class ProcessorFactory {

    private List<String> endpoints;

    enum Strategy {
        MULTICAST, ROUND_ROBIN, SELECTOR
    }

    public ProcessorFactory(List<String> endpoints) {
        this.endpoints = endpoints;
    }

    public Processor create(Strategy strategy) {
        switch(strategy) {
            case MULTICAST:
                return createMulticastProcessor(endpoints);
            case ROUND_ROBIN:
                return createRoundRobinProcessor(endpoints);
            case SELECTOR:
                return createSelectorProcessor(endpoints);
        }
        throw new IllegalArgumentException("Unknown strategy: " + strategy);
    }

    Processor createSelectorProcessor(List<String> endpoints) {
        // do complex things that we don't want to test
        return null;
    }

    Processor createRoundRobinProcessor(List<String> endpoints) {
        // do complex things that we don't want to test
        return null;
    }

    Processor createMulticastProcessor(List<String> endpoints) {
        // do complex things that we don't want to test
        return null;
    }
}

Solution:

Creating simple Mock is no go, because it mock all methods in a class/interface. What we want is to mock only part of the class and to do that we can use Spock Spy. Spy allows us to specify only the methods we want to mock and others leave from original object. In our case the test would look like this:

package com.farenda.spock

import spock.lang.Shared
import spock.lang.Specification

import static com.farenda.spock.ProcessorFactory.Strategy.*

class SpyTest extends Specification {

    @Shared def multicastProcessor = Mock(Processor)
    @Shared def roundRobinProcessor = Mock(Processor)
    @Shared def selectingProcessor = Mock(Processor)

    @Shared def endpoints = ['direct:x', 'direct:y']

    def factory = Spy(ProcessorFactory, constructorArgs: [endpoints]) {
        createMulticastProcessor(endpoints) >> multicastProcessor
    }

    def setup() {
        factory.createRoundRobinProcessor(endpoints) >> roundRobinProcessor
    }

    def 'should create selected processor'() {
        given:
        factory.createSelectorProcessor(endpoints) >> selectingProcessor

        when:
        def processor = factory.create(strategy)

        then:
        processor == expectedProcessor

        where:
        strategy    | expectedProcessor
        MULTICAST   | multicastProcessor
        ROUND_ROBIN | roundRobinProcessor
        SELECTOR    | selectingProcessor
    }

}

The code is fairly straightforward. Spy is created with, well, Spy method, which takes implementation class as the parameter and possibly some of its arguments. Here we pass endpoints as constructor parameter. What is interesting we can specify mocked methods on Spy in different places:

  • during Spy construction (createMulticastProcessor),
  • in setup phase (createRoundRobinProcessor),
  • in test itself (createSelectorProcessor).

Spock spies should not be overused, because it usually means that the code haven’t been written correctly (for example I’ve used Spock Spy only once during 4 years of using Spock Framework). Sometimes they are useful, though.

Share with the World!
Categories Spock Framework Tags unit-tests
Previous: AutoCleanup Spock test resources
Next: Java Timer/TimerTask example

Recent Posts

  • Java 8 Date Time concepts
  • Maven dependency to local JAR
  • Caesar cipher in Java
  • Java casting trick
  • Java 8 flatMap practical example
  • Linked List – remove element
  • Linked List – insert element at position
  • Linked List add element at the end
  • Create Java Streams
  • Floyd Cycle detection in Java

Pages

  • About Farenda
  • Algorithms and Data Structures
  • Bash Tutorial
  • Bean Validation Tutorial
  • Clojure Tutorial
  • Design Patterns
  • Java 8 Streams and Lambda Expressions Tutorial
  • Java Basics Tutorial
  • Java Collections Tutorial
  • Java Concurrency Tutorial
  • Java IO Tutorial
  • Java Tutorials
  • Java Util Tutorial
  • Java XML Tutorial
  • JUnit Tutorial
  • MongoDB Tutorial
  • Quartz Scheduler Tutorial
  • Software Developer’s Tools
  • Spock Framework Tutorial
  • Spring Framework

Tags

algorithms bash bean-validation books clojure design-patterns embedmongo exercises git gof gradle groovy hateoas hsqldb i18n java java-basics java-collections java-concurrency java-io java-lang java-time java-util java-xml java8 java8-files junit linux lists log4j logging maven mongodb performance quartz refactoring regex rest slf4j solid spring spring-boot spring-core sql unit-tests

Yet another programming solutions log © 2021

sponsored
We use cookies to ensure that we give you the best experience on our website. If you continue to use this site we will assume that you are happy with it.Ok