Writing a parameterized specification in Spock is easy. We need to add the
where: block and use data providers to specify different values. For each set of values from the data providers our specifications is run, so we can test for example very effectively multiple input arguments for a method and the expected outcome. A data provider can be anything that implements the
Iterable interface. Spock also adds support for a data table. In the data table we define columns for each variable and in the rows values for each variable. Since Spock 1.1 we can reuse the value of the variables inside the data provider or data table. The value of the variable can only be reused in variables that are defined after the variable we want to reuse is defined.
We all know writing tests or specifications with Spock is fun. We can run our specifications and when one of our assertions in a feature method invalid, the feature method is marked as failed. If we have more than one assertion in our feature method, only the first assertion that fails is returned as an error. Any other assertion after a failing assertion are not checked. To let Spock execute all assertions and return all failing assertions at once we must use the
verifyAll method. We pass a closure with all our assertions to the method. All assertions will be checked when use the
verifyAll and if one or more of the assertions is invalid the feature method will fail.
Sometimes we are working on a new feature in our code and we want to write a specification for it without yet really implementing the feature. To indicate we know the specification will fail while we are implementing the feature we can add the
@PendingFeature annotation to our specification method. With this annotation Spock will still execute the test, but will set the status to ignored if the test fails. But if the test passes the status is set to failed. So when we have finished the feature we need to remove the annotation and Spock will kindly remind us to do so this way.
When we write a feature method in our Spock specification to test our class we might run into long running methods that are invoked. We can specify a maximum time we want to wait for a method. If the time spent by the method is more than the maximum time our feature method must fail. Spock has the
@Timeout annotation to define this. We can apply the annotation to our specification or to feature methods in the specification. We specify the timeout value as argument for the
@Timeout annotation. Seconds are the default time unit that is used. If we want to specify a different time unit we can use the annotation argument
unit and use constants from
java.util.concurrent.TimeUnit to set a value.
To ignore feature methods in our Spock specification we can use the annotation
@Ignore. Any feature method or specification with this annotation is not invoked when we run a specification. With the annotation
@IgnoreRest we indicate that feature methods that do not have this annotation must be ignored. So any method with the annotation is invoked, but the ones without aren’t. This annotation can only be applied to methods and not to a specification class.
Although I couldn’t make it to Gr8Conf EU this year, I am glad a lot of the presentations are available as slide decks and videos. The slide deck for the talk Interesting nooks and crannies of Spock you (may) have never seen before by Marcin Zajączkowski is very interesting. This is really a must read if you use Spock (and why shouldn’t you) in your projects. One of the interesting things is the ability to change the response for methods in a class that is stubbed using Spock’s
Stub method, but have no explicit stubbed method definition.
In a previous post we learned that we can check a specific exception is not thrown in our specification with the
notThrown method. If we are not interested in a specific exception, but just want to check no exception at all is thrown, we must use the
noExceptionThrown method. This method return
true if the called code doesn’t throw an exception.
In a Spock specification we write our assertion in the
expect: blocks. If we need to write multiple assertions for an object we can group those with the
with method. We specify the object we want write assertions for as argument followed by a closure with the real assertions. We don’t need to use the
assert keyword inside the closure, just as we don’t have to use the
assert keyword in an
In the following example specification we have a very simple implementation for finding an
User object. We want to check that the properties
name have the correct value.
Creating and working with mocks and stubs in Spock is easy. If we want to interact with our mocks and stubs we have several options to return values. One of the options is the triple right shift operator
>>>. With this operator we can define different return values for multiple invocations of the stubbed or mocked method. For example we can use the
>>> operator followed by a list of return values
['abc', 'def', 'ghi']. On the first invocation
abc is return, the second invocation returns
def and the third (and following) invocation(s) return
In a previous blog post we have seen the
IgnoreIf extension. There is also a counterpart: the
Requires extension. If we apply this extension to a feature method or specification class than the method or whole class is executed when the condition for the
@Requires annotation is true. If the condition is false the method or specification is not executed. As a value for the
@Requires annotation we must specify a closure. In the closure Spock adds some properties we can use for our conditions:
jvm can be used to check a Java version or compatibility.
sys returns the Java system properties.
env used to access environment variables.
os can be used to check for operating system names.
javaVersion has the Java version as
BigDecimal, eg. 1.8.