Search code examples
groovyclosuresspockiterabledata-driven-tests

How to change the "data provider" returned from a closure into a "data provider"?


This is in the context of "data driven" testing with Spock:

where:
key << myDriver.myMap.keySet()

... works fine: the key values are delivered, the parameterised testing works.

But if I try this:

where:
key << { myDriver.myMap.keySet() } 

it doesn't work. The object then on the RHS of the << is a Closure. I've then tried numerous things to try to coax a "data provider" out of this Closure.

I want to put a closure there firstly so that I can debug a bit but also to provide a more complex set of permutations (not just of "key" values but values of other test parameters... see a recent question of mine here).

Perhaps it's not helped by the class delivered by keySet(): turns out this is a LinkedHashMap$LinkedKeySet... but it's obviously Iterable.

I'm a little bit mystified by this "data provider" category. In the Spock "tutorial" it says that this must implement Iterable. It doesn't say whether that's all its characteristics. Going

{ myDriver.myMap.keySet() }.iterator()

doesn't help... iterator() obviously delivers Iterator, not Iterable anyway. What I then get is horrors like this:

groovy.lang.MissingMethodException: No signature of method: core.MyModule.processCommand() is applicable for argument types: (core.UT_ForMyModule$__spock_feature_1_12prov0_closure8, joptsimple.OptionSet, java.util.ArrayList) values: [core.UT_ForMyModule$__spock_feature_1_12prov0_closure8@65fdd86b, ...]

... which clearly means it's delivering an Iterator which iterates over a Collection of precisely one Closure.

So, in short, how do I get an Iterable from a closure returning an Iterable?


Solution

  • Unless you have delayed execution objectives here, I believe just running the closure should do:

    key << { myDriver.myMap.keySet() }()
    

    But note that this will execute it in the statement.