Grails API Functional Testing

Examples of testing Grails APIs with Grails Rest Client Builder, Groovy Http Builder, and Apache Http Client.

Object Partners

You’ve written (or are about to write) an API in Grails. Which is quite easy, especially with all the REST API improvements in Grails 2.3. Now you want to ensure your API works correctly when the first users start hitting it with JSON. But you don’t want to write and maintain raw JSON strings - what are some existing libraries you could use to help make testing your API easier?

Let’s walk through some quick examples of testing a Grails API with the Grails Rest Client Builder plugin, the Groovy Http Builder library, and the Apache Fluent Http Client library. We’ll use JSON in these examples, but you could easily substitute XML if your API supports that format.

Create API

Let’s start with a simple Grails API for a Person class with a first and last name. We’ll use the Grails 2.3 @Resource annotation to quickly create the API from the domain class:

import grails.rest.Resource

@Resource(uri = '/person', formats = ['json'])
class Person implements Serializable {
  String firstName
  String lastName

  static constraints = {
    firstName(nullable: false)
    lastName(nullable: false)
  }
}

Enable Functional Test Phase

If your project doesn’t already have a plugin that enables functional testing (e.g. Geb, Webdriver, etc.), then you’ll need to add code similar to this to your scripts/_Events.groovy file to enable the functional test phase. I borrowed this code from the Functional Test plugin:

// If you have another plugin that enables functional tests,
// such as Geb, you won't need to do this
eventAllTestsStart = {
    if (getBinding().variables.containsKey("functionalTests")) {
        functionalTests << "functional"
    }
}

If you do have a plugin that enables the functional test phase, don’t add this to your _Events.groovy file. Otherwise your functional tests may run twice.

Grails Rest Client Builder

The Grails Rest Client Builder plugin is built to call Rest APIs from your application code, but it can easily be used to call APIs in your test as well. Here is a quick example of using a GET to retrieve a person:

  def 'should fetch person with Grails REST client builder'() {
    given:
    Person person = personRemoteControl.createPerson([firstName: 'Rest', lastName: 'Smith'])

    RestBuilder rest = new RestBuilder()

    when:
    RestResponse response = rest.get("http://localhost:8080/grails-api-testing/person/${person.id}") {
      // Need to set the accept content-type to JSON, otherwise it defaults to String
      // and the API will throw a 415 'unsupported media type' error
      accept JSON
    }

    then:
    assert response.status == 200
    assert response.json.firstName == person.firstName
    assert response.json.lastName == person.lastName
  }

One thing to note when issuing a GET with the REST client builder plugin - I had to set the ‘accept’ type to JSON. Otherwise the plugin defaulted to accepting the String type and the API complained that String was an unsupported type and threw a 415 error.

And using a POST to create a new Person:

  def 'should create a person with Grails REST client builder'() {
    given:
    String newFirstName = "RestNew"
    String newLastName = "Smith"

    RestBuilder rest = new RestBuilder()

    when:
    def response = rest.post("http://localhost:8080/grails-api-testing/person") {
      json {
        firstName = newFirstName
        lastName = newLastName
      }
    }

    then:
    assert response.status == 201
    assert personRemoteControl.findByFirstName(newFirstName)?.lastName == newLastName
  }

Groovy Http Builder

The Groovy Http Builder library provides a handy syntax to call APIs over Http. In these examples we’ll use the RESTClient subset of the Http Builder library since it is geared specifically towards calling Rest APIs and provides a more concise syntax for doing so.

First, we’ll issue a GET to fetch an existing Person:

  def 'should fetch a person with Groovy Http-Builder'() {
    given:
    Person person = personRemoteControl.createPerson([firstName: 'Httpbuilder', lastName: 'Smith'])

    RESTClient restClient = new RESTClient("http://localhost:8080/grails-api-testing/")

    when:
    def response = restClient.get(path: "person/${person.id}")

    then:
    assert response.status == 200
    assert response.data.firstName == person.firstName
    assert response.data.lastName == person.lastName
  }

Then we’ll POST a new Person to our API:

  def 'should create a person with Groovy Http-Builder'() {
    given:
    String newFirstName = "HttpNew"
    String newLastName = "Smith"

    RESTClient restClient = new RESTClient("http://localhost:8080/grails-api-testing/")

    when:
    def response = restClient.post(
        path: "person",
        body: [firstName: newFirstName, lastName: newLastName],
        contentType: groovyx.net.http.ContentType.JSON
    )

    then:
    assert response.status == 201
    assert personRemoteControl.findByFirstName(newFirstName)?.lastName == newLastName
  }

Apache Http Client

The Apache Http Client library is a popular, well-worn Java library that dates back over a decade, but it is still widely used. We’ll use it’s Fluent version for its powerful and readable builder-like syntax.

We’ll start with a GET to grab an existing Person:

  def 'should fetch a person with Apache Http Client Fluent'() {
    given:
    Person person = personRemoteControl.createPerson([firstName: 'Httpclient', lastName: 'Smith'])

    when:
    Content responseContent = Request.Get("http://localhost:8080/grails-api-testing/person/${person.id}")
        .execute()
        .returnContent()

    def json = JSON.parse(responseContent.toString())

    then:
    assert json.firstName == person.firstName
    assert json.lastName == person.lastName
  }

Then use a POST to create a new Person:

  def 'should create a new person with Apache Http Client Fluent'() {
    given:
    String newFirstName = "ApacheNew"
    String newLastName = "Smith"

    String jsonString = new JSON(firstName: newFirstName, lastName: newLastName)

    when:
    Request.Post("http://localhost:8080/grails-api-testing/person")
        .bodyString(jsonString, org.apache.http.entity.ContentType.APPLICATION_JSON)
        .execute()
        .returnContent()
    then:
    assert personRemoteControl.findByFirstName(newFirstName)?.lastName == newLastName
  }

PUT and DELETE

I also wrote tests for updating and deleting a Person with PUT and DELETE, those tests are available on GitHub: PUT test and DELETE test

Code

I hope these examples will give you a starting place to see what options are available to test your Grails API. And check out the full source code for this testing project on GitHub: https://github.com/craigatk/grails-api-testing

Happy testing!

Share this Post

Related Blog Posts

JVM

Groovys .with() and multiple assignment

July 9th, 2014

Groovy has a limitation that restricts multiple assignment to simple variables. However, by using with(), we may be able to work around that.

Igor Shults
JVM

Gradle Summit 2014 Recap

June 18th, 2014

Review of material and presentations from Gradle Summit 2014, Santa Clara, California.

Object Partners
JVM

Inline initialization of Java Maps

June 5th, 2014

Inline initialization of Java Maps is never pretty, this solution provides a type safe and efficient way to do so.

Neil Buesing

About the author