MFIhsan
MFIhsan

Reputation: 1057

Spock - How to check method invocation count on a Spy object?

I'm having tough time get this spock test to work.

I have a Spring repo/DAO class that invokes stored procedures multiple times. I'm trying to write a unit test that validates if the SP is invoked 'x' number of times (3 invocations to createSP() method).

public class PlanConditionRepositoryImpl{

    ....

    public void write() {
        for (int i=0; i<3; i++) {
            createSP(new ConditionGroup(), new Condition()).call();
        }
    }

    protected StoredProcedure<Void> createSP(ConditionGroup planConditionGroup, Condition planCondition) {
        return new StoredProcedure<Void>()
                .jdbcTemplate(getJdbcTemplate())
                .schemaName(SCHEMA_NAME);
    }
}       

However the below implementation is not doing that. How do I achieve the invocation count check? Or how do I avoid calling the actual implementation of createSP() method.

def write(){
    def repo = Spy(PlanConditionRepositoryImpl){
        createSP(_, _) >> Spy(StoredProcedure){
            call() >> {
                //do nothing
            }
        }
    }
    when:
    repo.write()

    then:
    3 * repo.createSP(_, _)
}

This is how I solved it using a hack. But is there a solution using Spock's interaction-based testing without introducing an extra variable?

def "spec"() {
    given:
    def count = 0
    def spy = Spy(PlanConditionRepositoryImpl){
        createSP(_, _) >> {count++}
    }

    when:
    spy.write()

    then:
    count == 3
}

Upvotes: 2

Views: 15341

Answers (1)

Opal
Opal

Reputation: 84824

What you need is a partial mock, have a look at the docs. However as I said partial mocking is basically bad practice and may indicate a bad design:

(Think twice before using this feature. It might be better to change the design of the code under specification.)

And about partial mocking:

// this is now the object under specification, not a collaborator
def persister = Spy(MessagePersister) {
  // stub a call on the same object
  isPersistable(_) >> true
}

when:
persister.receive("msg")

then:
// demand a call on the same object
1 * persister.persist("msg")

Here's how the test should be written:

@Grab('org.spockframework:spock-core:1.0-groovy-2.4')
@Grab('cglib:cglib-nodep:3.1')

import spock.lang.*

class Test extends Specification {
    def "spec"() {
        given:    
        def mock = Mock(StoredProcedure)
        def spy = Spy(PlanConditionRepositoryImpl) 

        when:
        spy.write()

        then:
        3 * spy.createSP() >> mock
        3 * mock.run()
    }
}

class PlanConditionRepositoryImpl {

    void write() {
        for (int i = 0; i < 3; i++) {
            createSP().run()
        }
    }

    StoredProcedure createSP() {
        new StoredProcedure()    
    }
}

class StoredProcedure {
    def run() {}
}

Upvotes: 5

Related Questions