Search code examples
javaunit-testinggroovyspockspock-spy

Spock Framework: problems with spying


I have an issue with using Spy in Spock, it either doesn't work as it should or my understanding is wrong so I'm trying to clarify this. Consider this code (Java):

public class CallingClass {

    public String functionOne() {
        //does stuff
        return "one";
    }

    public String functionTwo() {
        String one = functionOne();
        return "some string " + one;
    }
}

Now I want to test the fact that functionTwo calls functionOne as well as define the returned value from functionOne (imagine for instance if functionOne is really complicated and I don't want to execute it in my test just want to stub it and set it to return a certain value). For this i write the following test in Groovy (using Spock):

class CallingClassTest extends Specification {

    def "check that functionTwo calls functionOne"() {
        def c = Spy(CallingClass)
        c.functionOne() >> "mocked function return"

        when:
        def s = c.functionTwo()

        then:
        1 * c.functionOne()
        s == "some string mocked function return"
    }
}

In order to do things like this, Spock is asking me to have the cglib library, so my build file (in Gradle) looks something like this:

apply plugin: 'groovy'

repositories {
    mavenCentral()
}

dependencies {
    compile 'org.codehaus.groovy:groovy:latest.release'

    testCompile 'org.spockframework:spock-core:latest.release'
    testCompile 'junit:junit:latest.release'
    testCompile 'cglib:cglib-nodep:latest.release'

}

Now when I run the test, I expect the functionOne not to be called at all, and instead my stubbed out version to be used. Instead, I get this:

Condition not satisfied:

s == "some string mocked function return"
| |
| false
| 19 differences (44% similarity)
| some string (-)o(-------)n(-------)e(----)
| some string (m)o(cked fu)n(ction r)e(turn)
some string one

Condition not satisfied:

s == "some string mocked function return"
| |
| false
| 19 differences (44% similarity)
| some string (-)o(-------)n(-------)e(----)
| some string (m)o(cked fu)n(ction r)e(turn)
some string one

    at CallingClassTest.check that functionTwo calls functionOne(CallingClassTest.groovy:17)

Even more so, if I debug this and set a breakpoint in functionOne it gets called :(

What am I missing? Shouldn't my test use the stubbed functionOne provided and just return the string "mocked function return"?


Solution

  • It should be:

    @Grab('org.spockframework:spock-core:0.7-groovy-2.0')
    @Grab('cglib:cglib-nodep:3.1')
    
    import spock.lang.*
    
    class CallingClassTest extends Specification {
    
        def "check that functionTwo calls functionOne"() {
            def c = Spy(CallingClass)
    
            when:
            def s = c.functionTwo()
    
            then:
            1 * c.functionOne() >> "mocked function return"
            s == "some string mocked function return"
        }
    }
    
    public class CallingClass {
    
        public String functionOne() {
            "one"
        }
    
        public String functionTwo() {
            String one = functionOne()        
            "some string $one"
        }
    }
    

    When you both spy/mock and verify this is how return value should be specified.