In Grails we can write unit tests for controllers. We can check for example the results from a redirect()
or render()
method. To check the result from a forward()
action we can use the forwardedUrl
property of the mock response object. The format of the URL is very basic and has the following form: /grails/(controller)/(action).dispatch?(queryParameters)
. So we get the servlet representation of a Grails controller request. We can use this format to check if our forward()
method is correct in the unit test.
First we create a simple controller with a index()
action which invokes the forward()
method with a action and parameters:
package com.mrhaki.grails class BookController { def index() { forward action: 'show', params: [fromIndex: true, bookId: 200] } }
Now we write a test (with Spock of course) to check the values from the forward()
method in the mock response. The following specification contains code to parse the forwardedUrl
property. We get the /controller/action as String
and the parameters as Map
object. Using Groovy syntax we can check for the values with forwardedUrl
and forwardedParams
:
package com.mrhaki.grails import grails.test.mixin.TestFor import spock.lang.Specification @TestFor(BookController) class BookControllerSpecification extends Specification { def "index must forward to show action"() { when: controller.index() then: forwardedUrl == '/book/show' } def "index must set parameter fromIndex to value true and forward"() { when: controller.index() then: forwardedParams.fromIndex == 'true' } def "index must set parameter bookId to 200 and forward"() { when: controller.index() then: forwardedParams.bookId == '200' } private getForwardedParams() { parseResponseForwardedUrl()[1] } private String getForwardedUrl() { parseResponseForwardedUrl()[0] } private parseResponseForwardedUrl() { // Pattern for forwardedUrl stored in response. def forwardedUrlPattern = ~/\/grails\/(.*)?\.dispatch\?*(.*)/ // Match forwardedUrl in response with pattern. def matcher = response.forwardedUrl =~ forwardedUrlPattern def forwardUrl = null def forwardParameters = [:] if (matcher) { // Url is first group in pattern. We add '/' so it has the same format as redirectedUrl from response. forwardUrl = "/${matcher[0][1]}" // Parse parameters that are available in the forwardedUrl of the response. forwardParameters = parseResponseForwardedParams(matcher[0][2]) } [forwardUrl, forwardParameters] } private parseResponseForwardedParams(final String queryString) { // Query string has format paramName=paramValue¶m2Name=param2Value. & is optional. def parameters = queryString.split('&') // Turn the paramName=paramValue parts into a Map. def forwardParameters = parameters.inject([:]) { result, parameter -> def (parameterName, parameterValue) = parameter.split('=') result[parameterName] = parameterValue result } forwardParameters } }
Code written with Grails 2.2.2 and Spock 0.7-groovy-2.0