Grails 3.3 Integration Testing with Spock Mocks
It is easy to use the Spock Framework, shipped with Grails, to mock or stub a collaborator (such as a service) in our Grails unit tests.
The Testing chapter explains a bit about mocking collaborators, doWithSpring/doWithConfig callback methods, the FreshRuntime annotation to mock beans in tests — but they’re mainly for unit testing.
How about mocking beans in an integration test?
Example
What if we have a controller
class AnimalRegistrationController {
AnimalRegistrationService animalRegistrationService
def arrival(ArrivalCommand arrival) {
animalRegistrationService
.registerArrival(arrival)
.map { ArrivalErrorMessage aem ->
renderErrors(aem)
}.orElse {
render status: 200
}
}
}which calls a service, which calls a repository – which might do external calls which you don’t want to happen in an integration test.
class AnimalRegistrationService {
ArrivalRepository arrivalRepository
Optional registerArrival(Arrival arrival) {
arrivalRepository.registerArrival(arrival)
}
}Previously I wrote that Grails 3.3 has Spock 1.1 — which gave us a few new features to use such as a default answer for java.util.Optional…but it gave us more!
1. DetachedMockFactory and TestConfiguration
Now we also have a DetachedMockFactory we can use to declare mocks outside the hierarchy of a outside of a Specification, e.g. in a Spring configuration.
I got triggered by this article about Spring Integration testing, and I adjusted it to work for Grails 3.3 — which is based on Spring Boot but doesn’t quite use all the Spring annotations we’re used to in a vanilla Spring application.
So we create a configuration, specifically for testing, in src/test/groovy using a DetachedMockFactory like
import spock.mock.DetachedMockFactory
import org.springframework.boot.test.context.TestConfiguration
import org.springframework.context.annotation.Bean
...
@TestConfiguration
class TestRepositoryConfig {
private DetachedMockFactory factory = new DetachedMockFactory()
@Bean
ArrivalRepository arrivalRepository() {
factory.Mock(ArrivalRepository)
}
}2. Integration test
We can now use the mocked bean in our Grails 3 integration test, by injecting it by type using @Autowired. We can create the expectations as usual.
@Integration
class ArrivalApiIntegrationSpec extends Specification {
@Value('${local.server.port}')
Integer serverPort
@Autowired
ArrivalRepository mockedArrivalRepository
void "should create an arrival"() {
given:
1 * mockedArrivalRepository.registerArrival(_) >> {
Optional.empty()
}
when:
def response = new RestBuilder().post('http://localhost:{serverPort}/api/arrivals') {
urlVariables([serverPort: serverPort])
json {
animalId = 1
date = '2017-01-01'
}
}
then:
response.status == 200
}
}3. Dependency
For the above to work, you actually have to pull in one essential spock-lang dependency.
Add it to your build.gradle
dependencies {
...
testCompile 'org.spockframework:spock-core:1.1-groovy-2.4'
testCompile 'org.spockframework:spock-spring:1.1-groovy-2.4'Bada-bing. It’s done.
That’s it
We have now full control over our mocked beans, as if we were in a unit test.
| Reference: | Grails 3.3 Integration Testing with Spock Mocks from our JCG partner Ted Vinke at the Ted Vinke’s Blog blog. |




