Is there any method in Spock to transparently get the current running count when using data tables without the the need to have it as an explicit input parameter?
For example
class MathSpec extends Specification {
def "maximum of two numbers"(int a, int b, int c) {
expect:
Math.max(a, b) == c
println "this is row:" + $currentRowCount//??
where:
a | b | c
1 | 3 | 3
7 | 4 | 4
0 | 0 | 0
}
}
This is really ugly because iterationCount
is a private variable, but possible:
Example spec:
package de.scrum_master.app
import spock.lang.Specification
import spock.lang.Unroll
class PieceTest extends Specification {
@Unroll
def "do something with data table item #item"() {
expect:
println specificationContext
.currentIteration
.parent
.iterationNameProvider
.iterationCount
where:
item | anotherItem
"foo" | 333
"bar" | 444
"zot" | 555
}
}
Console log:
1
2
3
Please note that this only works for @Unroll
ed feature methods, not without that annotation.
Update: Expose iteration count via global Spock extension
Disclaimer: I love Spock but I am not fluent in Groovy meta programming. This is also my first Spock extension.
You may know built-in Spock extensions which are mostly annotation-driven, such as @Ignore
, @Timeout
, @Stepwise
, @Issue
, @AutoCleanup
. But there are also global extensions which are not described in the manual but still exist, e.g. ReportLogExtension
, IncludeExcludeExtension
.
Unfortunately the manual does not describe how to create such extensions, but with some googling and source code research you can find out. It is nothing for beginners, though.
Global Spock extension:
This extension adds a dynamic member iterationCount
to each Spock specification.
package de.scrum_master.app
import org.spockframework.runtime.AbstractRunListener
import org.spockframework.runtime.extension.AbstractGlobalExtension
import org.spockframework.runtime.model.FeatureInfo
import org.spockframework.runtime.model.IterationInfo
import org.spockframework.runtime.model.SpecInfo
class IterationCountExtension extends AbstractGlobalExtension {
@Override
void visitSpec(SpecInfo spec) {
spec.addListener(new IterationCountListener())
}
static class IterationCountListener extends AbstractRunListener {
MetaClass metaClass
int iterationCount
@Override
void beforeSpec(SpecInfo spec) {
println spec.name
metaClass = spec.reflection.metaClass
}
@Override
void beforeFeature(FeatureInfo feature) {
println " " + feature.name
iterationCount = 0
metaClass.iterationCount = iterationCount
}
@Override
void beforeIteration(IterationInfo iteration) {
println " " + iteration.name
metaClass.iterationCount = iterationCount++
}
}
}
Each extension needs to be registered. So please also add a file META-INF/services/org.spockframework.runtime.extension.IGlobalExtension
with the following content to your test resources:
de.scrum_master.app.IterationCountExtension
Showcase specification:
package de.scrum_master.app
import spock.lang.Specification
import spock.lang.Unroll
class SampleTest extends Specification {
def "no data table"() {
expect:
println " " + iterationCount
}
def "data table items"() {
expect:
println " " + iterationCount
where:
item | anotherItem
"foo" | 333
"bar" | 444
"zot" | 555
}
@Unroll
def "unrolled data table item"() {
expect:
println " " + iterationCount
where:
item | anotherItem
"foo" | 333
"bar" | 444
"zot" | 555
}
@Unroll
def "unrolled data table item #item"() {
expect:
println " " + iterationCount
where:
item | anotherItem
"foo" | 333
"bar" | 444
"zot" | 555
}
}
Console log:
SampleTest
no data table
no data table
0
data table items
data table items
0
data table items
1
data table items
2
unrolled data table item
unrolled data table item[0]
0
unrolled data table item[1]
1
unrolled data table item[2]
2
unrolled data table item #item
unrolled data table item foo
0
unrolled data table item bar
1
unrolled data table item zot
2
As you can see, the extension works regardless of whether @Unroll
is used or not. In this respect it is also better than the quick & dirty solution from above.
BTW, if you want the count to be 1-based instead of 0-based, just switch the expression iterationCount++
to ++iterationCount
in the extension listener method beforeIteration
.