Grails API Functional Testing
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:
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 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:
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:
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:
Then we’ll POST a new Person to our API:
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:
Then use a POST to create a new Person:
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!
Hi
This seems very useul but still i am missing some information in order to get the HTTPClient fluent api working
“unable to resolve class Content”, same ofr Request.
Are there additional dependencies or imports required?
Hi,
For enabling functional tests in Grails use the Grails Funky Spock Plugin (http://grails.org/plugin/funky-spock).
For consuming the API in functional specs, another great client is groovy-wslite (https://github.com/jwagenleitner/groovy-wslite). This client library is quite lighter than Groovy HTTP Builder. I really recommend you to give it a try.
Enjoy!
Nice post!
It helped me a lot.
I think it’s a good idea include in _Events.groovy this part from grails functional test plugin too:
eventTestSuiteStart = { String type ->
if (type == “functional”) {
testingBaseURL = argsMap[“baseUrl”] ?: “http://localhost:$serverPort$serverContextPath”
if (!testingBaseURL.endsWith(‘/’)) testingBaseURL += ‘/’
System.setProperty(“grails.functional.test.baseURL”, testingBaseURL)
}
}
You can use it in your tests:
def baseUrl
def setup() {
baseUrl = System.getProperty(“grails.functional.test.baseURL”)
println “baseUrl: $baseUrl”
}
def “test get something”() {
when:
def resp = restBuilder.get(“$baseUrl/something”)
…..
If you harcode the complete url you won’t be able to execute those tests to another server with the -baseUrl option