corky_bantam
corky_bantam

Reputation: 339

How do I iterate over tests in Grails Spock testing when I wish to perform the same tests on many similar fields?

I have a domain class with property pairs:

Boolean statement1
Boolean statement1Missing

These pairs number up to nine.

The following constraints apply to each pairing:

    statement1                  nullable: true
    statement1Missing           validator: {val, obj ->
                                    if ( val == true &&
                                        (obj.statement1 == true || obj.statement1 == false)) {
                                        return ['statement.not.missing', 1] 
                                    }
                                    if (obj.statement1 == null && val == false) {
                                        return ['statement.is.missing', 1]
                                    }
                                }

I have devised an integration test that can accommodate one pair of statements:

@Unroll
def "Validation of custom validation for statement1"() {

    given: "New data"
    def participant = new Data(studyId:     "M00001",
                                            formVersion:    Version.get(7)                          
                                           )

    and: "an initial set of test values"
    participant.statement1 = statement1
    participant.statement1Missing = statement1Missing

    when: "the validator is invoked"
    def isValidConsentData = participant.validate()

    then: "the appropriate fields are flagged as errors"
    isValidConsentData == anticipatedValid
    participant.errors.getFieldError(fieldInError)?.code == errorCode

    where:

    statement1  | statement1Missing | anticipatedValid  | fieldInError          | errorCode
    true        | false             | true              | null                  | null
    false       | false             | true              | null                  | null
    null        | true              | true              | null                  | null
    null        | false             | false             | "statement1Missing"   | "statement.is.missing"
    true        | true              | false             | "statement1Missing"   | "statement.not.missing"
    false       | true              | false             | "statement1Missing"   | "statement.not.missing"
}

This handles all the combinations for statement1 that I wish to test.

I have been trying to work out how I can repeat this test for all nine statement pairs. I have tried putting in a loop like this:

    (1..9).each { statementNo
        ...
        and ...
        participant.("statement" + statementNo) = ("statement" + statementNo)
        ...
        where:
        ("statement" + StatementNo) | ("statement" + StatementNo + Missing) | ...
    }

I have used this type of iteration before when wanting to iterate over properties, but it does not work in Spock. The test is just ignored completely. I really do not want to repeat this code for each statement pair.

I have investigated the use of this type of structure http://www.christianoestreich.com/2012/11/domain-constraints-grails-spock-updated/ but this only allows you to test one property value at a time, whereas I want to test one property value many times.

The other option is to explicitly include every property pair in the 'where' block and every possible outcome, but that would be very cumbersome.

Please provide some suggestions as to how I can use an iterative structure to perform these tests.

Upvotes: 0

Views: 778

Answers (1)

topr
topr

Reputation: 4612

How about something like:

...    

and: "an initial set of test values"
(1..9).each { statementNo ->
    participant."statement$statementNo" = statement
    participant."statement${statementNo}Missing" = statementMissing
}

when: "the validator is invoked"
def isValidConsentData = participant.validate()

then: "the appropriate fields are flagged as errors"
(1..9).each { statementNo ->
    def fieldInError
    if (anticipatedValid) {
        fieldInError = null
    } else {
        fieldInError = "statement${statementNo}Missing"
    }
    assert isValidConsentData == anticipatedValid
    assert participant.errors.getFieldError(fieldInError)?.code == errorCode
}

where:
statement  | statementMissing | anticipatedValid | errorCode
true       | false            | true             | null
false      | false            | true             | null
null       | true             | true             | null
null       | false            | false            | "statement.is.missing"
true       | true             | false            | "statement.not.missing"
false      | true             | false            | "statement.not.missing"

Not sure how it behaves for getFieldError(fieldName) when there are is no error for a given field so you may need to add some condition for the second assert using !anticipatedValid if exception would be thrown.

Important is that implicit assert are necessary as each is void thus there would be nothing checked by the test at all otherwise.

Upvotes: 2

Related Questions