Search code examples
groovyspockdata-driven-tests

Spock: Data Pipes, and Variable Assignments


From Spock documentation:

Data tables, data pipes, and variable assignments can be combined as needed:

...
where:
a | _
3 | _
7 | _
0 | _

b << [5, 0, 0]

c = a > b ? a : b

This simple example produces a MissingPropertyException for y.

def test() {
    expect:
        x == 42
    where:
        y = 12
        x << [y + 30, 54 - y]
}

What's wrong with this example?


Solution

  • You can't mix data pipe and variable assignment that way. Let's take a look at the source code. You can put a breakpoint in org.spockframework.runtime.ParameterizedSpecRunner class at line 49 and run the test with the debugger. You will see that currentFeature holds two parameters with names y and x:

    enter image description here

    You will also notice that there is a single dataProvider for variable name x defined:

    enter image description here

    This data provider exists because we have defined x as a data pipe, so it has to iterate over the list of variables and evaluate it in the context of data pipes. In this context it expects that y variable is also defined as a data pipe so it can take a value associated with the same index.

    If you define your where: as:

    where:
    y << [12, 12]
    x << [y + 30, 54 - y]
    

    your test would succeed, because now y variable exists as a data provider and evaluating values for x accesses values for y using second data provider.

    How to combine variable assignment with data pipes?

    Consider following example:

    @Unroll
    def "variable assignment example"() {
        expect:
        x == 42
    
        and:
        c
    
        where:
        y <<  [12, 12]
        x << [y + 30, 54 - y]
        c = y < x
    }
    

    In this case variable c is evaluated twice for each element in data pipes y and x. When the first unroll happens y = 12, x = y + 30 => 12 + 30 => 42 and c evaluates to true because y<x. When the second unroll happens 12 value is assigned to y again, x evaluates to 42 (54 - y => 54 - 12 => 42) and c evaluates to true again.

    Conclusion

    I see that it may look like simple y = 12 variable assignment should be discovered by data pipe evaluation. Unfortunately it does not work that way. When data pipe gets evaluated it can only use values from other data pipes and any variable assignment is not seen in this context.