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.
If we need to add a Java system property or change the value of a Java system property inside our specification, then the change is kept as long as the JVM is running. We can make sure that changes to Java system properties are restored after a feature method has run. Spock offers the
RestoreSystemProperties extension that saves the current Java system properties before a method is run and restores the values after the method is finished. We use the extension with the
@RestoreSystemProperties annotation. The annotation can be applied at specification level or per feature method.
Spcok has a lot of nice extensions we can use in our specifications. The
AutoCleanup extension makes sure the
close() method of an object is called each time a feature method is finished. We could invoke the
close() method also from the
cleanup method in our specification, but with the
@AutoCleanup annotation it is easier and immediately shows our intention. If the object we apply the annotation to doesn’t have a
close() method to invoke we can specify the method name as the value for the annotation. Finally we can set the attribute
true if we don’t want to see any exceptions that are raised when the
close() method (or custom method name, that is specified) is invoked.