Testing Grails with Spock
Harry
· 13 Sep 2026
· 2 views
Why Testing Matters
Tests make refactoring safe, keep applications stable, and define expected behavior. Grails ships with Spock, a testing framework whose given/when/then style is as readable as documentation.
Spock Basics
class SampleSpec extends Specification {
def "should do something"() {
given:
// setup
when:
// action
then:
// assertions
}
}Unit Testing Domain Classes
class UserSpec extends Specification {
void "username cannot be blank"() {
when:
def user = new User(username: "")
then:
!user.validate()
}
}Pure domain tests need no database.
Unit Testing Services
class UserServiceSpec extends Specification {
UserService userService
void "user creation works"() {
when:
userService.createUser([username: "admin"])
then:
User.count() == 1
}
}Mocking and Stubbing
Mocks isolate logic and keep external services out of tests:
def emailService = Mock(EmailService)
emailService.send(_, _) >> true
1 * emailService.send(_, _) // verify a call happened
// stub a failure and assert the app handles it
paymentService.charge(_) >> { throw new RuntimeException("Failed") }Data-Driven Tests
void "age validation"(int age, boolean valid) {
expect:
new User(age: age).validate() == valid
where:
age | valid
10 | false
18 | true
}Integration Testing
@Integration
@Rollback
class UserIntegrationSpec extends Specification {
void "save persists to database"() {
when:
new User(username: "test").save()
then:
User.count() == 1
}
}Integration tests load the full Grails context and @Rollback keeps the database clean.
Testing Controllers
class UserControllerSpec extends Specification {
def controller = new UserController()
def userService = Mock(UserService)
def setup() { controller.userService = userService }
void "index returns users"() {
when:
controller.index()
then:
response.text == "User Home"
}
}Test Best Practices
- Write unit tests first; add integration tests for critical paths.
- Mock external services - never call real ones in tests.
- Test negative paths and failure scenarios.
- Keep the suite fast and runtime under control.
- Run tests in CI and fail the build on failures.
Common Testing Mistakes
- Having no tests at all.
- Testing implementation instead of behavior.
- Over-mocking until nothing is really verified.
- Slow suites that nobody runs.
Key Points
- Spock's given/when/then reads like documentation.
- Unit tests need no database; integration tests use @Rollback.
- Mocks and data-driven tables keep tests fast.
- Automate tests in CI for lasting safety.