Introduction
Spock is a testing and specification framework for Java and Groovy applications with a beautiful and highly expressive specification language. Spock is compatible with most IDEs, build tools, and continuous integration servers.
Spock is inspired from JUnit, jMock, RSpec, Groovy, Scala, Vulcans, and other fascinating life forms.
Why Spock?
There are various reasons to use the Spock framework -
First, tests - specifications in Spock speak - written in Spock are well structured, expressive and therefore provide good readability.
In addition, Spock has built-in features like data driven testing and interaction based testing (mocking). Data Driven testing allows your test code to be reused, i.e. to be applied multiple times with different parameters.
Next, because Spock is a Groovy based DSL, specification code can become concise where the equivalent Java code would be overly verbose. As Groovy and Java can freely be mixed together you can use any Java based library you like, or use Groovy based libraries.
Finally Spring framework supports Groovy and - not surprisingly - Spring Test Context framework works well with Spock: application contexts can easily be made available to specifications via annotation, thus enabling integration testing at all levels.
Spock Basics
The test case is called as specification and the test method called as feature in Spock framework.
There are six kinds of blocks exist in Spock:
setup: The setup block is where we do any setup work for the feature that we are describing. It may not be preceded by other blocks, and may not be repeated. A setup block doesn't have any special semantics. The setup: label is optional and may be omitted, resulting in an implicit setup block. The given: label is an alias for setup:
when & then: The when and then blocks always occur together. They describe a stimulus and the expected response. Whereas when blocks may contain arbitrary code, then blocks are restricted to conditions, exception conditions, interactions, and variable definitions. A feature method may contain multiple pairs of when-then blocks.
expect: An expect block is more limited than a then block in that it may only contain conditions and variable definitions. It is useful in situations where it is more natural to describe stimulus and expected response in a single expression.
cleanup: A cleanup block may only be followed by a where block, and may not be repeated. Like a cleanup method, it is used to free any resources used by a feature method, and is run even if (a previous part of) the feature method has produced an exception. As a consequence, a cleanup block must be coded defensively; in the worst case, it must gracefully handle the situation where the first statement in a feature method has thrown an exception, and all local variables still have their default values.
where: A where block always comes last in a method, and may not be repeated. It is used to write data-driven feature methods.
Spock Integration testing with Spring Boot:
For writing the integration test using Spock, we would need to include following dependencies in our build.gradle file:
1) testCompile("org.spockframework:spock-core:0.7-groovy-2.0")
2) testCompile("org.spockframework:spock-spring:0.7-groovy-2.0")
3) testCompile("org.springframework.boot:spring-boot-starter-test")
Also we need to include groovy plugin by adding “ apply plugin: 'groovy ' ” in our build file.
And for testing our RESTAPIs, we can use RestTemplate or RestClient.
We have to use few annotations
@ContextConfiguration(loader = SpringApplicationContextLoader.class, classes = [Application.class])
// For loading the spring context, we use ContextConfiguration annotation, we can also pass the required classes for specification using the classes attribute of this annotation
@WebAppConfiguration //For loading the web application context
@IntegrationTest("server.port:0")
//For integration test, server.port:0 has a special meaning. It suggests that during the execution of specification, it will run the application on random port.
@Stepwise // To execute test cases in order
@Value('${local.server.port}') //We can get the port value using this annotation
int port;
@Shared
If we want to use a variable across different features in a specification then we can use @Shared annotation.
Example Code:
A sample application with few sample integration test cases is available in git repository with the URL
https://github.com/badalb/spring-security-spock.git
How to run the specifications?
'gradle build' command will run the specifications and build the project. If you want to run only specifications then we can use 'gradle test --info' command.
For skipping the test we can use the command 'gradle build -x test'.
Once the server is up, then it will execute all the specifications. After execution it will generate the test report and the embedded server will get shutdown.
After running the specifications the output will be displayed on index.html (/build/reports/tests/index.html):