Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Could we have multi-dimensional where clauses? #1062

Open
woldie opened this issue Dec 6, 2019 · 5 comments
Open

Could we have multi-dimensional where clauses? #1062

woldie opened this issue Dec 6, 2019 · 5 comments

Comments

@woldie
Copy link

@woldie woldie commented Dec 6, 2019

Would it be possible to express multi-dimensional test data by allowing a sequence of two or more where clauses?

package com.example

import spock.lang.Specification

class ComplexProblemTest extends Specification {
  @Unroll
  def 'it will always exceed 0: #description'(String description, int w, int x, int y, int z) {
    expect:
    (w + x) * (y + z) > 0

    where:
    description   | w | x | y  | z
    'w 01 series' | 0 | 1 | -1 | 5
    'w 01 series' | 0 | 1 | -7 | 8
    'w 01 series' | 0 | 1 | 0  | 1
    'w 01 series' | 0 | 1 | 1  | 0
    'w 02 series' | 0 | 2 | -1 | 5
    'w 02 series' | 0 | 2 | -7 | 8
    'w 02 series' | 0 | 2 | 0  | 1
    'w 02 series' | 0 | 2 | 1  | 0
    'w 13 series' | 1 | 3 | -1 | 5
    'w 13 series' | 1 | 3 | -7 | 8
    'w 13 series' | 1 | 3 | 0  | 1
    'w 13 series' | 1 | 3 | 1  | 0
    'w 14 series' | 1 | 4 | -1 | 5
    'w 14 series' | 1 | 4 | -7 | 8
    'w 14 series' | 1 | 4 | 0  | 1
    'w 14 series' | 1 | 4 | 1  | 0
  }
}

becomes:

package com.example

import spock.lang.Specification

class ComplexProblemTest extends Specification {
  @Unroll
  def 'it will always exceed 0: #description'(String description, int w, int x, int y, int z) {
    expect:
    (w + x) * (y + z) > 0

    where:
    y  | z
    -1 | 5
    -7 | 8
    0  | 1
    1  | 0

    where:
    description   | w | x
    'w 01 series' | 0 | 1
    'w 02 series' | 0 | 2
    'w 13 series' | 1 | 3
    'w 14 series' | 1 | 4
  }
}

Huh? Why? Okay, I have some tests where I have an invariant assertion, like "the computation is greater than 0" or "the call throws a ValidationException", and the test data consists of two or more groups of data that I am manually building out a where table with all the permutations.

Given that I am a totally error-prone human and also so so so so so lazy, it'd be cool if Spock could do the permutations for me. I think it would be possible to do multi-dimensional where and still enforce that the full set of variables always appear in the test method's parameter list. That validation would, I think, help the user grok the proper (limited) utility of multi-dimensional where as part of their ongoing learning curve for Spock.

Finally, I speculate it would be possible to do that interesting array subscript thing you do with the test method name when it doesn't change due to templated strings when you @Unroll over a multi-dimensional where.

So, in the @Unroll'ed names in the multi-dimensional where example above, you could know by the variables used that there's a "partially templated" test method name. And, you could name the test function permutations in the following way to make it easier for the user to pinpoint which combination of input data has a failure condition when they do fail. For example:

it will always exceed 0: w 01 series[0] PASSED
it will always exceed 0: w 01 series[1] PASSED
it will always exceed 0: w 01 series[2] PASSED
it will always exceed 0: w 01 series[3] PASSED
it will always exceed 0: w 02 series[0] PASSED
it will always exceed 0: w 02 series[1] PASSED
it will always exceed 0: w 02 series[2] PASSED
it will always exceed 0: w 02 series[3] PASSED
it will always exceed 0: w 13 series[0] PASSED
it will always exceed 0: w 13 series[1] PASSED
it will always exceed 0: w 13 series[2]: [Condition not satisfied: ...
it will always exceed 0: w 13 series[3] PASSED
it will always exceed 0: w 14 series[0] PASSED
it will always exceed 0: w 14 series[1] PASSED
it will always exceed 0: w 14 series[2] PASSED
it will always exceed 0: w 14 series[3] PASSED

Thanks for Spock! It makes my Outside-In TDD work bearable and helps me put food on the table!

@woldie

This comment has been minimized.

Copy link
Author

@woldie woldie commented Dec 6, 2019

EDIT: the first example code block had bad copy pasta and I corrected it.

@Vampire

This comment has been minimized.

Copy link
Member

@Vampire Vampire commented Dec 7, 2019

You know that you don't need to use tables?
You can also otherwise calculate the data providers.
And you can use any Groovy feature and any library and any own code to do so.

And if you unroll a method with some pattern, it is your responsibility to make the names unique. (at least currently)

Look at this which produces exactly the use-cases you wanted and also has distinguishable names, that are not only unique, but also meaningful and not simply counted from 0 to 3:

@Unroll
def 'it will always exceed 0: w #w#x series (y: #y, z: #z)'() {
    expect:
        (w + x) * (y + z) > 0

    where:
        [w, x, y, z] <<
            [
                [
                    [0, 1],
                    [0, 2],
                    [1, 3],
                    [1, 4]
                ],
                [
                    [-1, 5],
                    [-7, 8],
                    [ 0, 1],
                    [ 1, 0]
                ]
            ]
                .combinations()
                *.flatten()
}
@Vampire

This comment has been minimized.

Copy link
Member

@Vampire Vampire commented Dec 7, 2019

grafik

@woldie

This comment has been minimized.

Copy link
Author

@woldie woldie commented Dec 7, 2019

@leonard84

This comment has been minimized.

Copy link
Member

@leonard84 leonard84 commented Jan 10, 2020

I think extending the data table syntax would add confusion, there are other requests for just joining multiple tables into one, so that you could split long lines into multiple tables.

Test should be easy to read, and if possible intuitively to understand whats happening. This feature does not satisfy those requirements IMHO.

Using the groovy collection methods, like @Vampire has shown you, is way more powerful and lets you do other things like permutations, filtering and so on.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
3 participants
You can’t perform that action at this time.