Spock: using a Mock inside a “where” clause table?
Question
I am trying to use ia mocked object in the table of a "where" clause. Basically something like this:
def "my test"(){
given:
InjectedObject1 inj1 = Mock()
InjectedObject2 inj2 = Mock()
SystemUnderTest system = new System(inj1, inj2)
MockedObject mocked = Mock()
inj1.someMethod() >> list // this will be a list of MockedObject
when:
system.execute()
then:
n * inj2.someOtherMethod()
where:
list | n
[mocked] | 0
[mocked, mocked] | 1
}
This doesn't work because the "where" clause is executed before the "given" clause, so mocked
doesn't exist yet when it is first referenced. How do I overcome this? mocked
in used only is this test so I'd like to avoid creating it outside of this method.
Note that this is a simplified example, there are actually more interactions, and other columns in the table that have an influence on n
- which makes the table syntax very handy.
Solution
You can refactor the method to something like:
...
inj1.someMethod() >> [mocked] * numReturned
...
then:
numCalled * inj2.someOtherMethod()
where:
numReturned | numCalled
1 | 0
2 | 1
In other words, specify (just) the parts in the where-block and assemble them in the method body. This is a common solution.
Usually, another solution is to shuffle the objects to be used in the where-block into @Shared
fields. The 'too big scope' problem can be mitigated by having multiple small specs in the same file. However, this solution won't work for mocks because mocks can't be @Shared
.