September 18, 2017

Spocklight: Group Assertions With verifyAll

We all know writing tests or specifications with Spock is fun. We can run our specifications and when one of our assertions in a feature method invalid, the feature method is marked as failed. If we have more than one assertion in our feature method, only the first assertion that fails is returned as an error. Any other assertion after a failing assertion are not checked. To let Spock execute all assertions and return all failing assertions at once we must use the verifyAll method. We pass a closure with all our assertions to the method. All assertions will be checked when use the verifyAll and if one or more of the assertions is invalid the feature method will fail.

In the following example specification we have 3 assertions in the feature method check all properties are valid. We don't use the verifyAll method in our first example.

// File: verifyall.groovy
@Grab('org.spockframework:spock-core:1.1-groovy-2.4')
import spock.lang.Specification
import spock.lang.Subject

class CourseSpec extends Specification {

    @Subject
    private course = new Course()
    
    void 'check all properties are valid'() {
        given:
        course.with {
            name = 'G'
            location = 'T'
            numberOfDays = 0
        }
    
        expect:
        with(course) {
            name.size() > 2
            location.size() > 2
            numberOfDays > 0
        }
    }

}

class Course {
    String name
    String location
    int numberOfDays
}

Let's see what happens when we don't use the verifyAll method and run the specification:

$ groovy verifyall.groovy
JUnit 4 Runner, Tests: 1, Failures: 1, Time: 28
Test Failure: check all properties are valid(CourseSpec)
Condition not satisfied:

name.size() > 2
|    |      |
G    1      false

 at CourseSpec.check all properties are valid_closure2(verifyall.groovy:21)
 at groovy.lang.Closure.call(Closure.java:414)
 at spock.lang.Specification.with(Specification.java:186)
 at CourseSpec.check all properties are valid(verifyall.groovy:20)

In the next example we use verifyAll to group the assertions for our course object:

// File: verifyall.groovy
@Grab('org.spockframework:spock-core:1.1-groovy-2.4')
import spock.lang.Specification
import spock.lang.Subject


class CourseSpec extends Specification {

    @Subject
    private course = new Course()
    
    void 'check all properties are valid'() {
        given:
        course.with {
            name = 'G'
            location = 'T'
            numberOfDays = 0
        }
    
        expect:
        with(course) {
            verifyAll {
                name.size() > 2
                location.size() > 2
                numberOfDays > 0
            }
        }
    }

}

class Course {
    String name
    String location
    int numberOfDays
}

We re-run the specification and now we get different output with all three assertions mentioned:

$ groovy verifyall.groovy
JUnit 4 Runner, Tests: 1, Failures: 1, Time: 26
Test Failure: check all properties are valid(CourseSpec)
Condition failed with Exception:

with(course) { verifyAll { name.size() > 2 location.size() > 2 numberOfDays > 0 } }

 at CourseSpec.check all properties are valid(verifyall.groovy:20)
Caused by: org.junit.runners.model.MultipleFailureException: There were 3 errors:
  org.spockframework.runtime.ConditionNotSatisfiedError(Condition not satisfied:

name.size() > 2
|    |      |
G    1      false
)
  org.spockframework.runtime.ConditionNotSatisfiedError(Condition not satisfied:

location.size() > 2
|        |      |
T        1      false
)
  org.spockframework.runtime.ConditionNotSatisfiedError(Condition not satisfied:

numberOfDays > 0
|            |
0            false
)
 at CourseSpec.$spock_feature_0_0_closure2$_closure3(verifyall.groovy:24)
 at CourseSpec.$spock_feature_0_0_closure2$_closure3(verifyall.groovy)
 at groovy.lang.Closure.call(Closure.java:414)
 at spock.lang.Specification.verifyAll(Specification.java:223)
 at CourseSpec.check all properties are valid_closure2(verifyall.groovy:21)
 at groovy.lang.Closure.call(Closure.java:414)
 at spock.lang.Specification.with(Specification.java:186)
 ... 1 more

Written with Spock 1.1-groovy-2.4.