We’ve come across a very peculiar behaviour with mocks and sets in Spock.
In a Spock (0.5, Groovy 1.7) given: block (amount is an Integer):
Set<Operand> operands=new HashSet<Operand>()
for (index in amount){
operand = Mock(Operand)
operand.update() >> null
operands.add(operand)
}
After each loop run (breakpoint on closing bracket), there’s only one (1) element in the set, when the loop starts anew, operands.size() == 0. Apparently, the mock objects mysteriously disappear.
In the following version, everything works and the set has operands.size() == amount after the loop runs.
Set<Operand> operands=new HashSet<Operand>()
amount.times{
operand = Mock(Operand)
operand.update() >> null
operands.add(operand)
}
Does anyone have an idea why the first version does not work?
The problem is unrelated to Spock (and
Sets).for (index in amount)is simply not a correct way to write a loop withamountiterations in Groovy. Afterin, Groovy expects something that it knows how to iterate over (e.g. anIterable). The fallback is to (logically) treat an object as a collection containing just itself. This explains why you get just one iteration whereindex == amount.The shortest way to write a loop with
amountiterations isamount.times {}, as in your second snippet.