Spock is a testing and specification framework for Java and Groovy applications. What makes it stand out from the crowd is its beautiful and highly expressive specification language. This plugin brings the power of Spock to Grails.
Version 0.3 of this plugin is not compatible with Grails 1.2.0, please use the 0.4-SNAPSHOT version which must be installed with an explicit version number.
If you have any questions or suggestions, please contact us through the Spock discussion forum (or its Nabble mirror). You can also raise an issue in the issue tracker. Sources for the Spock plugin can be found on Google code
Installation
Type: "grails install-plugin spock 0.4-SNAPSHOT"
Appetizer
Here is a very simple Grails unit specification in Spock…
import grails.plugin.spock.*class MySpec extends UnitSpec {
def "domain mocking"() {
setup:
mockDomain(Person) when:
new Person(name: name).save() then:
Person.findByName(name) != null where:
name = "bill"
}
}Before using this plugin, head on over to the
Spock project site and get familiar with Spock.
Running Tests
Tests are run just like normal Grails tests via
grails test-app . A new “spock” test type is added to the unit, integration and functional phases. You can use the Grails 1.2
test type targeting feature to run
only your Spock tests…
Class names of Spock tests must end in either "Spec" or "Specification". Otherwise, the Grails test runner won't find them.
Base Specifications
Several grails specific specification super classes are also provided to make testing your Grails app even easier. These classes for the most part mirror the existing Grails classes such as
GrailsUnitTestCase .
All of these classes are in the
grails.plugin.spock package.
UnitSpec
The
UnitSpec class mirrors the
GrailsUnitTestCase class. It features all of the
mock* methods that this class has such as
mockDomain ,
mockForConstraintsTests etc.
The example at the start of this page is an example of using
UnitSpec .
ControllerSpec
The
ControllerSpec class mirrors the
ControllerUnitTestCase (+) class. It is a subclass of
UnitSpec (so is designed for unit testing) that tests a controller based on the class name. For example,
MyControllerSpec will test
MyController .
The controller…
class MyController {
def text = {
render "text"
} def someRedirect = {
redirect(action: "someRedirect")
} def bodyElementText = {
render request.'XML'.body.text()
} def model = {
[a: '1']
}
}The specification…
import grails.plugin.spock.*class MyControllerSpec extends ControllerSpec { def 'text action'() {
when:
controller.text() then:
mockResponse.contentAsString == "text"
} def 'some redirect action'() {
when:
controller.someRedirect() then:
redirectArgs == [action: "someRedirect"]
} def 'bodyElementText action'() {
when:
xmlRequestContent = requestContent and:
controller.bodyElementText() then:
mockResponse.contentAsString == value where:
value << ['value', 'value']
requestContent << ["<request><body>value</body></request>", { request { body('value') } }]
} def 'model action'() {
expect:
controller.model() == [a: '1']
}
}TagLibSpec
The
TagLibSpec class is suitable for testing tag libs. It is a subclass of
UnitSpec (so is designed for unit testing) that tests a tag lib based on the class name. For example,
MyTagLibSpec will test
MyTagLib .
The tag lib…
class MyTagLib {
def bar = { attrs, body ->
out << "<p>Hello World!</p>"
} def bodyTag = { attrs, body ->
out << "<${attrs.name}>"
out << body()
out << "</${attrs.name}>"
}
}import grails.plugin.spock.*class MyTagLibSpec extends TagLibSpec { def 'bar tag'() {
expect:
bar() == "<p>Hello World!</p>"
} def 'bar tag subsequent call'() {
expect:
bar() == "<p>Hello World!</p>"
bar() == "<p>Hello World!</p>"
} def 'body tag'() {
expect:
bodyTag(name: 'a') { "Foo" } == "<a>Foo</a>"
bodyTag(name: 'b') { "Bar" } == "<b>Bar</b>"
}
}IntegrationSpec
The
IntegrationSpec class is the base class for integration tests (i.e.
test/integration ). It supports autowiring of beans in the application context…
import grails.plugin.spock.IntegrationSpecclass MyIntegrationSpec extends IntegrationSpec {
def myService // will be autowired /* Spock tests */
}Like regular Grails integration tests, all tests run in a database transaction that is rolled back. You can disable this behaviour by setting
transactional to false…
import grails.plugin.spock.IntegrationSpecclass MyIntegrationSpec extends IntegrationSpec {
static transactional = false /* Spock tests */
}GroovyPagesSpec
The
GroovyPagesSpec is a kind of integration test that is useful for
integration test GSP code.
For example:
import grails.plugin.spock.*class FormatBooleanTagSpec extends GroovyPagesSpec { def "simple format boolean usage"() {
when:
template = '<g:formatBoolean boolean="${flag}" true="T" false="F" />'
params = [flag: flag]
body = null then:
output == letter where:
flag << [true, false]
letter << ['T', 'F']
}
}The pattern is
always to set
template , and optionally
params and/or
body in the
when clause, and then check the
output in the
then clause.
FunctionalSpec
The
FunctionalSpec class can be used to perform functional tests of your application via
HTMLUnit
This functional testing features borrow heavily from the grails-functional-test plugin, but is not quite the same.A big thanks goes out to all who contributed to that plugin, which was the inspiration for these features.
Functional specifications work by providing a
session object configured to point at the local grails app. This
session object is an instance of
grails.plugin.spock.functional.WebSession which is a groovier API to the HTMLUnit class
WebClient.
For extra convenience, functional specification automatically delegates method calls and property gets and sets to this session object.
import grails.plugin.spock.*class MyFunctionalSpec extends FunctionalSpec { def simpleService // bean properties are autowired def 'register for something'() {
when:
get("/registration")
form('registrationForm').with {
name = "Luke Daley"
click 'register'
} then:
response.contentAsString =~ 'Thanks for registering'
}}
Documentation on this functional testing is very lacking at the moment. Expect it to improve over the coming days.For now, you can check out the WebSession source and specification.
Help & Community
Mailing Lists
Consider joining the Spock
mailing list to join the Spock community.
Grails specific Spock issues can be raised on that list, or the normal Grails user list.
Reporting Issues
Any issues encountered with either Spock, or this plugin, can be raised in the Spock
issue tracker.