Grails 2+ (at the moment 2.3) and unit tests with controllers that use chain()

While testing the new version 2.3 of the Grails-Framework I stumbled over the problem that since version 2.0 chainArgs is not supported anymore in unit-tests. You can still test controllers with chain() as I found out, and it is actually more intuitive, but unfortunately I couldn't find any documentation on this, but succeeded after a while of trying hard.

The chain action is now encoded in response.redirectUrl und the chainModel in controller.chainModel, so it is not conveniently in one place anymore but at least it's there.

Example with Spock (default testing library since Grails 2.3)

class FooController {

    def springSecurityService

    def register(RegisterCommand rc) {
        User currentUser = springSecurityService.currentUser as User
        if (springSecurityService.loggedIn && currentUser) {
            flash.error = message(code: "error.register-while-already-logged-in")
            redirect action: "show", params: [id: currentUser.id]
        } else {
            if (request.method == 'POST') {
                chain action: "handleRegisterForm", model: [rc: rc]
            } else
                [rc: new RegisterCommand()]
        }
    }

    def handleRegisterForm(RegisterCommand rc) {
        render "Not yet implemented"
    }
}

And the test as follows:

@TestFor(FooController)
@Mock([User])
@Stepwise
class FooControllerUnitSpec extends Specification {

    RegisterCommand rc
    User testUser
    SpringSecurityService springSecurityService = Mock(SpringSecurityService)

    def setup() {
        //create a valid RegisterCommand
        rc = mockCommandObject(RegisterCommand) as RegisterCommand
        rc.username = "TestUser"
        rc.email = "test@test.com"
        rc.emailCheck = "test@test.com"
        rc.password = "1Ijd_dheIp"
        rc.passwordCheck = "1Ijd_dheIp"
        rc.receiveEmail = true
        rc.acceptTOS = true

        User.metaClass.encodePassword = {-> } // necessary because of the methods in the User class

        testUser = new User(
                username: "Test",
                email: "test@test.de",
                password: "passwd222",
                enabled: true
        ).save()

        controller.springSecurityService = springSecurityService
    }

    def cleanup() {
    }

    void "valid post requests to register() should be chained to handleRegisterForm()"() {
        when:
        request.method = 'POST'
        controller.register(rc)
        then:
        1 * springSecurityService.getCurrentUser() >> null
        1 * springSecurityService.isLoggedIn() >> false
        response.redirectedUrl== '/foo/handleRegisterForm' && controller.chainModel.rc
    }
}
Share/Save