Reputation: 339
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
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