Pablo Pazos
Pablo Pazos

Reputation: 3216

Grails 2.4.4 generated controller test fails

I have test for the save action of a controller. It just executes the action with correct params, but the problem is on the redirectedUrl line: it is null.

Using the app, after saving the domain instance, I get the redirection to the show action and the show view is rendered correctly.

Any clues of what's the problem here?

The controller:

@Transactional(readOnly = true)
class FolderController {

    static allowedMethods = [save: "POST", update: "PUT", delete: "DELETE"]
    ...

    @Transactional
    def save(Folder folderInstance) {

        if (folderInstance == null) {
            notFound()
            return
        }

        if (folderInstance.ehrId)
        {
           def ehr = ehr.Ehr.get(folderInstance.ehrId)
           ehr.directory = folderInstance
           ehr.save() 
        }

        if (folderInstance.hasErrors()) {
            respond folderInstance.errors, view:'create'
            return
        }

        folderInstance.save flush:true

        request.withFormat {
            form multipartForm {
                flash.message = message(code: 'default.created.message', args: [message(code: 'folder.label', default: 'Folder'), folderInstance.id])
                redirect folderInstance
            }
            '*' { respond folderInstance, [status: CREATED] }
        }
    }
    ...
}

The test:

@TestFor(FolderController)
@Mock(Folder)
class FolderControllerSpec extends Specification {

        ...
    void "Test the save action correctly persists an instance"() {

        when:"The save action is executed with a valid instance"
            response.reset()
            populateValidParams(params)
            def folder = new Folder(params)

            controller.save(folder)
            println folder.errors // no errors

        then:"A redirect is issued to the show action"
            response.redirectedUrl == '/folder/show/1'
            controller.flash.message != null
            Folder.count() == 1
    }
    ...
}

The output:

junit.framework.AssertionFailedError: Condition not satisfied:

response.redirectedUrl == '/folder/show/1'
|        |             |
|        null          false
org.codehaus.groovy.grails.plugins.testing.GrailsMockHttpServletResponse@112b2f1

    at directory.FolderControllerSpec.Test the save action correctly persists an instance(FolderControllerSpec.groovy:61)

Upvotes: 0

Views: 573

Answers (2)

Pablo Pazos
Pablo Pazos

Reputation: 3216

I forgot to add the allowedMethods field.

The first problem was that the generated tests doesn't sets the right request method for the correspondent actions, so to call .save() this is needed: controller.request.method = "POST"

Then what @user1690588 suggested (request.format = 'form') did the trick to get the right redirectedUrl.

My final test looks like this:

void "Test the save action correctly persists an instance"() {

    when:"The save action is executed with a valid instance"
        response.reset()
        populateValidParams(params)
        def folder = new Folder(params)

        controller.request.method = "POST"
        request.format = 'form'

        controller.save(folder)

    then:"A redirect is issued to the show action"
        response.redirectedUrl == '/folder/show/1'
        controller.flash.message != null
        Folder.count() == 1
}

Upvotes: 1

MKB
MKB

Reputation: 7619

Grails scaffold controllers are smarter controllers. They respect the request format and generate the response accordingly.

For example your save action -- it redirects to the show action if the request format is form otherwise it returns saved domain instance with status CREATED.

Following code is responsible for this

request.withFormat {
    form multipartForm {
        flash.message = message(code: 'default.created.message', args: [message(code: 'folder.label', default: 'Folder'), folderInstance.id])
        redirect folderInstance
    }
    '*' { respond folderInstance, [status: CREATED] }
}

And in you test cases, your request is not of form type and hence redirectedUrl is null.

To make form request, add following code in you test case before making save call--

request.format = 'form'

Hope this helps.

Upvotes: 1

Related Questions