Spocklight: Including or Excluding Specifications Based On Annotations
One of the lesser known and documented features of Spock if the external Spock configuration file. In this file we can for example specify which specifications to include or exclude from a test run. We can specify a class name (for example a base specification class, like DatabaseSpec
) or an annotation. In this post we see how to use annotations to have some specifications run and others not.
The external Spock configuration file is actually a Groovy script file. We must specify a runner
method with a closure argument where we configure basically the test runner. To include specification classes or methods with a certain annotation applied to them we configure the include
property of the test runner. To exclude a class or method we use the exclude
property. Because the configuration file is a Groovy script we can use everything Groovy has to offer, like conditional statements, println
statements and more.
Spock looks for a file named SpockConfig.groovy
in the classpath of the test execution and in in the USER_HOME/.spock
directory. We can also use the Java system property spock.configuration
with a file name for the configuration file.
In the following example we first define a simple annotation Remote
. This annotation can be applied to a class or method:
package com.mrhaki.spock
import java.lang.annotation.ElementType
import java.lang.annotation.Retention
import java.lang.annotation.RetentionPolicy
import java.lang.annotation.Target
@Target([ElementType.TYPE, ElementType.METHOD])
@Retention(RetentionPolicy.RUNTIME)
@interface Remote {
}
We write a simple Spock specification where we apply the Remote
annotation to one of the methods:
package com.mrhaki.spock
import spock.lang.Specification
class WordRepositorySpec extends Specification {
@Remote // Apply our Remote annotation.
def "test remote access"() {
given:
final RemoteAccess access = new RemoteAccess()
expect:
access.findWords('S') == ['Spock']
}
def "test local access"() {
given:
final LocalAccess access = new LocalAccess()
expect:
access.findWords('S') == ['Spock']
}
}
Next we create a Spock configuration file:
import com.mrhaki.spock.Remote
runner {
// This is Groovy script and we
// add arbitrary code.
println "Using RemoteSpockConfig"
// Include only test classes or test
// methods with the @Remote annotation
include Remote
// Alternative syntax
// to only look for annotations.
// include {
// annotation Remote
// }
// We can also add a condition in
// the configuration file.
// In this case we check for a Java
// system property and if set the
// specs with @Remote are not run.
if (System.properties['spock.ignore.Remote']) {
exclude Remote
}
}
When we run the WordRepositorySpec
and our configuration file is on the classpath only the specifications with the @Remote
annotation are executed. Let's apply this in a simple Gradle build file. In this case we save the configuration file as src/test/resources/RemoteSpockConfig.groovy
, we create a new test task remoteTest
and set the Java system property spock.configuration
:
apply plugin: 'groovy'
repositories {
jcenter()
}
dependencies {
compile 'org.codehaus.groovy:groovy-all:2.4.4'
testCompile 'org.spockframework:spock-core:1.0-groovy-2.4'
}
// New test task with specific
// Spock configuration file.
task remoteTest(type: Test) {
// This task belongs to Verification task group.
group = 'Verification'
// Set Spock configuration file when running
// this test task.
systemProperty 'spock.configuration', 'RemoteSpockConfig.groovy'
}
Now when we execute the Gradle test
task all specifications are executed:
And when we run remoteTest
only the specification with the @Remote
annotation are executed:
Written with Gradle 2.6 and Spock 1.0-groovy-2.4.
The code is available on Github