Spocklight: Include or Exclude Specifications Based On Class or Interface
In a previous post we saw how can use the Spock configuration file to include or exclude specifications based on annotations. Instead of using annotations we can also use classes to include or exclude specifications. For example we could have a base specification class DatabaseSpecification
. Other specifications dealing with databases extend this class. To include all these specifications we use the DatabaseSpecification
as value for the include
property for the test runner configuration.
Because Java (and Groovy) doesn't support real multiple inheritance this might be a problem if we already have specifications that extends a base class, but the base class cannot be used as filter for the include
and exclude
runner configuration. Luckily we can also use an interface as the value for the inclusion or exclusion. So we could simple create a marker interface and implement this interface for these specifications we want to include or exclude from the test execution.
We rewrite the sample from our previous post to show how we can use a marker interface. First we take a look at the interface definition:
package com.mrhaki.spock
interface RemoteSpec {
}
We used the @Remote
annotation on a specification method, but an interface is implemented on class. Therefore we must refactor our specification into three classes. First we create a base specification class:
package com.mrhaki.spock
import spock.lang.Specification
import spock.lang.Subject
abstract class WordRepositorySpec extends Specification {
@Subject
S access
def "test remote or local access"() {
expect:
access.findWords('S') == ['Spock']
}
}
Next we write two new specification classes that extends this abstract class and each uses a different implementation for the class under test.
package com.mrhaki.spock
class LocalWordRepositorySpec
extends WordRepositorySpec {
def setup() {
access = new LocalAccess()
}
}
package com.mrhaki.spock
class RemoteWordRepositorySpec
extends WordRepositorySpec // Implement RemoteSpec marker interface
implements RemoteSpec {
def setup() {
access = new RemoteAccess()
}
}
Instead of using an annotation we use the marker interface RemoteSpec
to include it for our test execution in the following configuration:
import com.mrhaki.spock.RemoteSpec
runner {
println "Using RemoteSpockConfig"
// Include only test classes that
// implement the RemoteSpec interface.
include RemoteSpec
// Alternative syntax
// to only look for classes or interfaces.
// include {
// baseClass RemoteSpec
// }
// 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 interface RemoteSpec
// are not run.
if (System.properties['spock.ignore.Remote']) {
exclude RemoteSpec
}
}
If we run the specifications with the same Gradle build file as the previous post we see that with the default test
task all specifications are executed:
And when we execute the remoteTest
task only the RemoteWordRepositorySpec
is executed:
Written with Gradle 2.6 and Spock 1.0-groovy-2.4.
Code is available on Github