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
    }
}

2. 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.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s