Spock mock returns wrong value

10,303

This is expected and documented behavior. If you want to mock and stub on the same mock, you have to do it in one line like

1 * mockDao.readCounter(_, _, _, _, _) >> dbValue

Here the relevant section:

Combining Mocking and Stubbing

Mocking and stubbing go hand-in-hand:

1 * subscriber.receive("message1") >> "ok"
1 * subscriber.receive("message2") >> "fail"

When mocking and stubbing the same method call, they have to happen in the same interaction. In particular, the following Mockito-style splitting of stubbing and mocking into two separate statements will not work:

setup:
subscriber.receive("message1") >> "ok"

when:
publisher.send("message1")

then:
1 * subscriber.receive("message1")

As explained in Where to Declare Interactions, the receive call will first get matched against the interaction in the then: block. Since that interaction doesn’t specify a response, the default value for the method’s return type (null in this case) will be returned. (This is just another facet of Spock’s lenient approach to mocking.). Hence, the interaction in the setup: block will never get a chance to match.

NOTE | Mocking and stubbing of the same method call has to happen in the same interaction.

Share:
10,303
Behzad Pirvali
Author by

Behzad Pirvali

Updated on June 17, 2022

Comments

  • Behzad Pirvali
    Behzad Pirvali almost 2 years

    I have got a strange use case where spock mock is returning the correct value when I do not check for two calls on the mocked class in the 'then:' section, but it is returning 0 when I include two checks in the 'then:' section. This is the mock:

    mockDao.readCounter(_, _, _, _, _) >> dbValue
    

    and here is the 'then:' section that fails:

    1 * mockDao.readCounter(_, _, _, _, _)
    // updateCounters is called with: sum = dbValue + value
    1 * mockDao.updateCounter(namespace, date, key, min, shardID, dbValue + value)
    

    In this case, instead of 'dbValue', '0' is returned. But if I comment out either of the two checks, then it passes. So, the following two cases pass:

    //1 * mockDao.readCounter(_, _, _, _, _)
    // updateCounters is called with: sum = dbValue + value
    1 * mockDao.updateCounter(namespace, date, key, min, shardID, dbValue + value)
    
    OR
    
    1 * mockDao.readCounter(_, _, _, _, _)
    // updateCounters is called with: sum = dbValue + value
    //1 * mockDao.updateCounter(namespace, date, key, min, shardID, dbValue + value)
    

    Here is the gradle section for spock:

    // spock
    testCompile "org.codehaus.groovy:groovy:2.4.7"
    compile group: 'org.spockframework', name: 'spock-core', version: '1.0-groovy-2.4'
    
    // !!! To get none-interface base mocking to work with Spock
    compile group: 'cglib', name: 'cglib-nodep', version: '3.2.4'