Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spock mock returns wrong value

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'
like image 465
Behzad Pirvali Avatar asked Jan 25 '17 00:01

Behzad Pirvali


1 Answers

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.

like image 50
Vampire Avatar answered Oct 13 '22 13:10

Vampire