Loading...

May 11, 2016

Grails Goodness: Use Random Server Port In Integration Tests

Because Grails 3 is based on Spring Boot we can use a lot of the functionality of Spring Boot in our Grails applications. For example we can start Grails 3 with a random available port number, which is useful in integration testing scenario's. To use a random port we must set the application property server.port to the value 0. If we want to use the random port number in our code we can access it via the @Value annotation with the expression ${local.server.port}.

Let's create a very simple controller with a corresponding integration test. The controller is called Sample:

// File: grails-app/controllers/mrhaki/SampleController.groovy
package mrhaki

class SampleController {

    def index() { 
        respond([message: 'Grails 3 is awesome!'])
    }
}

We write a Spock integration test that will start Grails and we use the HTTP Requests library to access the /sample endpoint of our application.

// File: src/integration-test/groovy/mrhaki/SampleControllerIntSpec.groovy
package mrhaki

import com.budjb.httprequests.HttpClient
import com.budjb.httprequests.HttpClientFactory
import grails.test.mixin.integration.Integration
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
import spock.lang.Specification

@Integration
class SampleControllerIntSpec extends Specification {
    
    /**
     * Server port configuration for Grails test 
     * environment is set to server.port = 0, which
     * means a random available port is used each time
     * the application starts.
     * The value for the port number is accessible
     * via ${local.server.port} in our integration test.
     */
    @Value('${local.server.port}')
    Integer serverPort

    /**
     * HTTP test client from the HTTP Requests library:
     * http://budjb.github.io/http-requests/latest
     */
    @Autowired
    HttpClientFactory httpClientFactory

    private HttpClient client

    def setup() {
        // Create HTTP client for testing controller.
        client = httpClientFactory.createHttpClient()
    }

    void "sample should return JSON response"() {
        when:
        // Nice DSL to build a request.
        def response = client.get {
            // Here we use the serverPort variable.
            uri = "http://localhost:${serverPort}/sample"
            accept = 'application/json'
        }
        
        then:
        response.status == 200
        
        and:
        final Map responseData = response.getEntity(Map)
        responseData.message == 'Grails 3 is awesome!'
    }
}

Finally we add the server.port to the application configuration:

# File: grails-app/conf/application.yml
...
environments:
    test:
        server:
            port: 0 # Random available port
...

Let's run the integration test: $ grails test-app mrhaki.SampleControllerIntSpec -integration. When we open the test report and look at the standard output we can see that a random port is used:

Written with Grails 3.1.6.