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