spock
spock copied to clipboard
Allow access to the currently executing block object
In order to improve the error reporting of our testing utils, we would like to have a ISpecificationContext#getCurrentBlock()
method.
If the code is before any block, it should return a block of type SETUP
and no text.
Ideally, the text of blocks returned by this method would have resolved #references
, similar to the spec titles.
@ddimtirov have you found any way to get the current block? I can access the list of blocks but I haven't found a way to determine which block is currently being executed
@pniederw, are there any options we have overlooked? It would be really helpful to have a block-level interception point for Spock extensions so as to enable power users or toolsmiths to help themselves. See also #645 and StackOverflow questions like this one.
I mean, this is easy to achieve, but it only works before/after feature execution:
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.SpecInfo
class LabelPrintExtension extends AbstractGlobalExtension {
@Override
void visitSpec(SpecInfo spec) {
spec.addListener(new LabelPrintListener())
}
static class LabelPrintListener extends AbstractRunListener {
@Override
void beforeFeature(FeatureInfo feature) {
feature.blocks.each {
println "$it.kind: ${it.texts[0]}"
}
}
}
}
META-INF/services/org.spockframework.runtime.extension.IGlobalExtension:
de.scrum_master.app.LabelPrintExtension
Update: There also seems to be a related (maybe half-baked, I have not tried) PR #111. But that one may just be an improvement concerning report generation, I have not actually inspected the code and would have a hard time fully understanding it.
FYI, if you need a workaround until PR #111 is available as a feature, see my StackOverflow answer which I am quoting here. By using src/test/resources/SpockConfig.groovy
and declaring a printing method named _
therein as a mixin to Specification
we can achieve that the method is also available in subclasses such as GebSpec
, GebReportingSpec
or your own (base) classes derived from either of them.
import spock.lang.Specification
class LabelPrinter {
def _(def message) {
println message
true
}
}
Specification.mixin LabelPrinter
Now if we have a spec like this (please note the unobtrusive underscores, e.g. given:_ "blah"
):
package de.scrum_master.testing
import spock.lang.Specification
class MySpockTest extends Specification {
def "interaction"() {
given:_ "My given comment"
def foo = 11
def bar = foo + 4
println "blah"
expect:_ "My expect comment"
interaction {
foo = 2
bar = 5
true
}
println "foo"
foo * bar == 10
foo + bar == 7
and:_ "My and comment"
true
}
}
We get a console log like this:
My given comment
blah
My expect comment
foo
My and comment
Let me just says that we plan to enhance reporting in post 1.1 so this feature won't be added in 1.1. One part is iteration-reporting #705 and the release of spock-reporting and spock-gradle plugin, another would be a block-listener support.
Me personally, I am not so much interested in reporting because I do not use it. Block listeners is what I am waiting for because I rather look into build logs, not into build reports.
My little workaround has the advantage to also work for and:
labels which would probably require some changes (such as not removing and:
from the AST as mere syntactic sugar) in Spock. It can also utilise variable/expression expansion inside "labels" (in reality GroovyString method parameters) in simple or unrolled specs, e.g. then:_ "hello $my_var"
.
BTW, it cannot be used with where:
, but the same probably also applies to a future block listener because of the special semantics of where:
.
Yes where
blocks are special and won't be part of the block listeners. There is also the hidden mechanic, that interactions from the then
blocks, are configured just before the preceding when
block and I'm not so sure if and how we would address this with the block listeners.
Is there any chance to have this move forward? It will be very useful in reporting to know which is the failing step
I've just been experimenting moving our integration tests from Cucumber over to Spock, which we run from a standalone distribution built using gradle application plugin. Unfortunately it looks like a bit of a non starter if Spock can't print tests as they're run.
@adrian-baker, is "non-starter" not a bit exaggerated? I would not want to be without Spock + Geb for any other set of tools. I also like to see this little shortcoming improved, abut this is very far from a non-starter. But of course you are free to opt out and just not use Spock.
Meanwhile you can use my workaround from above - quite easy and effective. And once this ticket is implemented, it shall be very easy to globally search and replace all the _
prefixes in your codebase later.
Like several times before, I have just answered another StackOverflow question concerning block listener support. Spock 2.0-M2 is already out and if there has not been a feature freeze yet, I would be very pleased if this would make it into the next milestone and then into the stable release.
@kriegaex You are spot on!
I am trying to make this workaround work right now.
The use case:
-
We want to have logs from the tests, that are similar to the generated spock-reports.
-
We are using Zalenium to run our tests against, which records videos, and allows to set cookies with messages, which will pop up during those recordings. These pop ups should be synchronised with the aforementioned logs.
Unfortunately, this workaround is breaking the spock-reports, as the property featureInfo.blocks.texts
will be an empty array, if the text is not of type String
.
I also noticed, that the _
method is actually (potentially) clashing with / shadowing public static final Object _ = Wildcard.INSTANCE;
in Specification
, so I used __
but this did not make any difference.