Spock has some great features to write specifications or tests that are short and compact. One of them is the old()
method. The old()
method can only be used in a then:
block. With this method we get the value a statement had before the when:
block is executed.
Let's see this with a simple example. In the following specification we create a StringBuilder
with an initial value. In the then:
block we use the same initial value for the assertion:
package com.mrhaki.spock class SampleSpec extends spock.lang.Specification { def "after addition of a new value the content is the initial value with the appended value"() { given: final StringBuilder builder = new StringBuilder('Spock ') when: builder << appendValue then: builder.toString() == 'Spock ' + appendValue where: appendValue << ['rocks!', 'is fun.', 'amazes.'] } }
If we want to change the initial value when we create the StringBuilder
we must also change the assertion. We can refactor the feature method and show our intention of the specification better. We add the variable oldToString
right after we have created the StringBuilder
. We use this in the assertion.
package com.mrhaki.spock class SampleSpec extends spock.lang.Specification { def "after addition of a new value the content is the initial value with the appended value"() { given: final StringBuilder builder = new StringBuilder('Spock ') final String oldToString = builder.toString() when: builder << appendValue then: builder.toString() == oldToString + appendValue where: appendValue << ['rocks!', 'is fun.', 'amazes.'] } }
But with Spock we can do one better. Instead of creating an extra variable we can use the old()
method. In the assertion we replace the variable reference oldToString
with old(builder.toString())
. This actually means we want the value for builder.toString()
BEFORE the when:
block is executed. The assertion also is now very clear and readable and the intentions of the specification are very clear.
package com.mrhaki.spock class SampleSpec extends spock.lang.Specification { def "after addition of a new value the content is the initial value with the appended value"() { given: final StringBuilder builder = new StringBuilder('Spock ') when: builder << appendValue then: builder.toString() == old(builder.toString()) + appendValue where: appendValue << ['rocks!', 'is fun.', 'amazes.'] } }
Let's change the specification a bit so we get some failures. Instead of adding the appendValue
data variable unchanged to the StringBuilder
we want to add a capitalized value.
package com.mrhaki.spock class SampleSpec extends spock.lang.Specification { def "after addition of a new value the content is the initial value with the appended value"() { given: final StringBuilder builder = new StringBuilder('Spock ') when: builder << appendValue.capitalize() then: builder.toString() == old(builder.toString()) + appendValue where: appendValue << ['rocks!', 'is fun.', 'amazes.'] } }
If we run the specification we get assertion failures. In the following output we see such a failure and notice the value for the old()
is shown correctly:
Condition not satisfied: builder.toString() == old(builder.toString()) + appendValue | | | | | | | | | Spock | rocks! | | | Spock rocks! | | false | | 1 difference (91% similarity) | | Spock (R)ocks! | | Spock (r)ocks! | Spock Rocks! Spock Rocks!
Note: If we use the old()
method we might get an InternalSpockError
exception when assertions fail. The error looks something like: org.spockframework.util.InternalSpockError: Missing value for expression "..."
. Re-ordering the assertion can help solve this. For example putting the old()
method statement last. In Spock 1.0-SNAPSHOT this error doesn't occur.
For more information we can read Rob Fletcher's blog post about the old()
method.
Code written with Spock 0.7-groovy-2.0.