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.
Spock is able to change the execution order of test methods in a specification. We can tell Spock to re-run failing methods before successful methods. And if we have multiple failing or successful tests, than first run the fastest methods, followed by the slower methods. This way when we re-run the specification we immediately see the failing methods and could stop the execution and fix the errors. We must set the property
optimizeRunOrder in the
runner configuration of the Spock configuration file. A Spock configuration file with the name
SpockConfig.groovy can be placed in the classpath of our test execution or in our
USER_HOME/.spock directory. We can also use the Java system property
spock.configuration and assign the filename of our Spock configuration file.
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
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.
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.