15.1.1 Unit Testing Controllers 3.1.4

See the light - agile, industrial strength, rapid web application development made easy

(Quick Reference) # 15.1.1 Unit Testing Controllers - Reference Documentation Authors: Graeme Rocher, Peter Ledbrook, Marc Palmer, Jeff Brown, Luke Daley, Burt Beckwith, Lari Hotari Version: 3.1.4 ## 15.1.1 Unit Testing Controllers #### The Basics You use the `grails.test.mixin.TestFor` annotation to unit test controllers. Using `TestFor` in this manner activates the `grails.test.mixin.web.ControllerUnitTestMixin` and its associated API. For example:

    import grails.test.mixin.TestFor
    import spock.lang.Specification@TestFor(SimpleController)
    class SimpleControllerSpec extends Specification {    void "test something"() {
        }
    }
Adding the `TestFor` annotation to a controller causes a new `controller` field to be automatically created for the controller under test. The `TestFor` annotation will also automatically annotate any public methods starting with "test" with JUnit 4's @Test annotation. If any of your test method don't start with "test" just add this manually To test the simplest "Hello World"-style example you can do the following:
    // Test class
    class SimpleController {
        def hello() {
            render "hello"
        }
    }

    import grails.test.mixin.TestFor
    import spock.lang.Specification@TestFor(SimpleController)
    class SimpleControllerSpec extends Specification {    void "test hello"() {
            when:
            controller.hello()        then:
            response.text == 'hello'
        }
    }
The `response` object is an instance of `GrailsMockHttpServletResponse` (from the package `org.codehaus.groovy.grails.plugins.testing`) which extends Spring's `MockHttpServletResponse` class and has a number of useful methods for inspecting the state of the response. For example to test a redirect you can use the `redirectedUrl` property:
    class SimpleController {
        def index() {
            redirect action: 'hello'
        }
        …
    }

    import grails.test.mixin.TestFor
    import spock.lang.Specification@TestFor(SimpleController)
    class SimpleControllerSpec extends Specification {    void 'test index'() {
            when:
            controller.index()        then:
            response.redirectedUrl == '/simple/hello'
        }
    }
Many actions make use of the parameter data associated with the request. For example, the 'sort', 'max', and 'offset' parameters are quite common. Providing these in the test is as simple as adding appropriate values to a special `params` variable:

    import grails.test.mixin.TestFor
    import spock.lang.Specification@TestFor(PersonController)
    class PersonControllerSpec extends Specification {    void 'test list'() {
            when:
            params.sort = 'name'
            params.max = 20
            params.offset = 0
            controller.list()        then:
            // …
        }
    }
You can even control what type of request the controller action sees by setting the `method` property of the mock request:

    import grails.test.mixin.TestFor
    import spock.lang.Specification@TestFor(PersonController)
    class PersonControllerSpec extends Specification {    void 'test save'() {
            when:
            request.method = 'POST'
            controller.save()        then:
            // …
        }
    }
This is particularly important if your actions do different things depending on the type of the request. Finally, you can mark a request as AJAX like so:

    import grails.test.mixin.TestFor
    import spock.lang.Specification@TestFor(PersonController)
    class PersonControllerSpec extends Specification {    void 'test list'() {
            when:
            request.method = 'POST'
            request.makeAjaxRequest()
            controller.getPage()        then:
            // …
        }
    }
You only need to do this though if the code under test uses the `xhr` property on the request. #### Testing View Rendering To test view rendering you can inspect the state of the controller's `modelAndView` property (an instance of `org.springframework.web.servlet.ModelAndView`) or you can use the `view` and `model` properties provided by the mixin:
    class SimpleController {
        def home() {
            render view: "homePage", model: [title: "Hello World"]
        }
        …
    }

    import grails.test.mixin.TestFor
    import spock.lang.Specification@TestFor(SimpleController)
    class SimpleControllerSpec extends Specification {    void 'test home'() {
            when:
            controller.home()        then:
            view == '/simple/homePage'
            model.title == 'Hello World'
        }
    }
Note that the view string is the absolute view path, so it starts with a '/' and will include path elements, such as the directory named after the action's controller. #### Testing Template Rendering Unlike view rendering, template rendering will actually attempt to write the template directly to the response rather than returning a `ModelAndView` hence it requires a different approach to testing. Consider the following controller action:
    class SimpleController {
        def display() {
            render template:"snippet"
        }
    }
In this example the controller will look for a template in `grails-app/views/simple/_snippet.gsp`. You can test this as follows:

    import grails.test.mixin.TestFor
    import spock.lang.Specification@TestFor(SimpleController)
    class SimpleControllerSpec extends Specification {    void 'test display'() {
            when:
            controller.display()        then:
            response.text == 'contents of the template'
        }
    }
However, you may not want to render the real template, but just test that is was rendered. In this case you can provide mock Groovy Pages:

    import grails.test.mixin.TestFor
    import spock.lang.Specification@TestFor(SimpleController)
    class SimpleControllerSpec extends Specification {    void 'test display with mock template'() {
            when:
            views['/simple/_snippet.gsp'] = 'mock template contents'
            controller.display()        then:
            response.text == 'mock template contents'
        }
    }
#### Testing Actions Which Return A Map When a controller action returns a `java.util.Map` that `Map` may be inspected directly to assert that it contains the expected data:
    class SimpleController {
        def showBookDetails() {
            [title: 'The Nature Of Necessity', author: 'Alvin Plantinga']
        }
    }

    import grails.test.mixin.TestFor
    import spock.lang.Specification@TestFor(SimpleController)
    class SimpleControllerSpec extends Specification {    void 'test show book details'() {
            when:
            def model = controller.showBookDetails()        then:
            model.author == 'Alvin Plantinga'
        }
    }
#### Testing XML and JSON Responses XML and JSON response are also written directly to the response. Grails' mocking capabilities provide some conveniences for testing XML and JSON response. For example consider the following action:
    def renderXml() {
        render(contentType:"text/xml") {
            book(title:"Great")
        }
    }
This can be tested using the `xml` property of the response:

    import grails.test.mixin.TestFor
    import spock.lang.Specification@TestFor(SimpleController)
    class SimpleControllerSpec extends Specification {    void 'test render xml'() {
            when:
            controller.renderXml()        then:
            response.text == "<book title='Great'/>"
            response.xml.@title.text() == 'Great'
        }
    }
The `xml` property is a parsed result from Groovy's XmlSlurper class which is very convenient for parsing XML. Testing JSON responses is pretty similar, instead you use the `json` property:
    // controller action
    def renderJson() {
        render(contentType:"application/json") {
            book = "Great"
        }
    }

    import grails.test.mixin.TestFor
    import spock.lang.Specification@TestFor(SimpleController)
    class SimpleControllerSpec extends Specification {    void 'test render json'() {
            when:
            controller.renderJson()        then:
            response.text == '{"book":"Great"}'
            response.json.book == 'Great'
        }
    }
The `json` property is an instance of `org.codehaus.groovy.grails.web.json.JSONElement` which is a map-like structure that is useful for parsing JSON responses. #### Testing XML and JSON Requests Grails provides various convenient ways to automatically parse incoming XML and JSON packets. For example you can bind incoming JSON or XML requests using Grails' data binding:
    def consumeBook(Book b) {
        render "The title is ${b.title}."
    }
To test this Grails provides an easy way to specify an XML or JSON packet via the `xml` or `json` properties. For example the above action can be tested by specifying a String containing the XML:

    import grails.test.mixin.TestFor
    import grails.test.mixin.Mock
    import spock.lang.Specification@TestFor(SimpleController)
    @Mock([Book])
    class SimpleControllerSpec extends Specification {
        void 'test consume book xml'() {
            when:
            request.xml = '<book><title>Wool</title></book>'
            controller.consumeBook()        then:
            response.text == 'The title is Wool.'
        }
    }
Or alternatively a domain instance can be specified and it will be auto-converted into the appropriate XML request:

    import grails.test.mixin.TestFor
    import grails.test.mixin.Mock
    import spock.lang.Specification@TestFor(SimpleController)
    @Mock([Book])
    class SimpleControllerSpec extends Specification {    void 'test consume book xml'() {
            when:
            request.xml = new Book(title: 'Shift')
            controller.consumeBook()        then:
            response.text == 'The title is Shift.'
        }
    }
The same can be done for JSON requests:

    import grails.test.mixin.TestFor
    import grails.test.mixin.Mock
    import spock.lang.Specification@TestFor(SimpleController)
    @Mock([Book])
    class SimpleControllerSpec extends Specification {    void 'test consume book json'() {
            when:
            request.json = new Book(title: 'Shift')
            controller.consumeBook()        then:
            response.text == 'The title is Shift.'
        }
    }
If you prefer not to use Grails' data binding but instead manually parse the incoming XML or JSON that can be tested too. For example consider the controller action below:
    def consume() {
        request.withFormat {
            xml {
                render "The XML Title Is ${request.XML.@title}."
            }
            json {
                render "The JSON Title Is ${request.JSON.title}."
            }
        }
    }
To test the XML request you can specify the XML as a string:

    import grails.test.mixin.TestFor
    import spock.lang.Specification@TestFor(SimpleController)
    class SimpleControllerSpec extends Specification {    void 'test consume xml'() {
            when:
            request.xml = '<book title="The Stand"/>'
            controller.consume()        then:
            response.text == 'The XML Title Is The Stand.'
        }    void 'test consume json'() {
            when:
            request.json = '{title:"The Stand"}'
            controller.consume()        then:
            response.text == 'The JSON Title Is The Stand.'
        }
    }
#### Testing Mime Type Handling You can test mime type handling and the `withFormat` method quite simply by setting the request's `contentType` attribute:
    // controller action
    def sayHello() {
        def data = [Hello:"World"]
        request.withFormat {
            xml { render data as grails.converters.XML }
            json { render data as grails.converters.JSON }
            html data
        }
    }

    import grails.test.mixin.TestFor
    import spock.lang.Specification@TestFor(SimpleController)
    class SimpleControllerSpec extends Specification {    void 'test say hello xml'() {
            when:
            request.contentType = 'application/xml'
            controller.sayHello()        then:
            response.text == '<?xml version="1.0" encoding="UTF-8"?><map><entry key="Hello">World</entry></map>'
        }    void 'test say hello json'() {
            when:
            request.contentType = 'application/json'
            controller.sayHello()        then:
            response.text == '{"Hello":"World"}'
        }
    }
There are constants provided by `ControllerUnitTestMixin` for all of the common common content types as shown below:

    import grails.test.mixin.TestFor
    import spock.lang.Specification@TestFor(SimpleController)
    class SimpleControllerSpec extends Specification {    void 'test say hello xml'() {
            when:
            request.contentType = XML_CONTENT_TYPE
            controller.sayHello()        then:
            response.text == '<?xml version="1.0" encoding="UTF-8"?><map><entry key="Hello">World</entry></map>'
        }    void 'test say hello json'() {
            when:
            request.contentType = JSON_CONTENT_TYPE
            controller.sayHello()        then:
            response.text == '{"Hello":"World"}'
        }
    }
The defined constants are listed below:
Constant | Value
--- | ---
ALL_CONTENT_TYPE | */*
FORM_CONTENT_TYPE | application/x-www-form-urlencoded
MULTIPART_FORM_CONTENT_TYPE | multipart/form-data
HTML_CONTENT_TYPE | text/html
XHTML_CONTENT_TYPE | application/xhtml+xml
XML_CONTENT_TYPE | application/xml
JSON_CONTENT_TYPE | application/json
TEXT_XML_CONTENT_TYPE | text/xml
TEXT_JSON_CONTENT_TYPE | text/json
HAL_JSON_CONTENT_TYPE | application/hal+json
HAL_XML_CONTENT_TYPE | application/hal+xml
ATOM_XML_CONTENT_TYPE | application/atom+xml
#### Testing Duplicate Form Submissions Testing duplicate form submissions is a little bit more involved. For example if you have an action that handles a form such as:
    def handleForm() {
        withForm {
            render "Good"
        }.invalidToken {
            render "Bad"
        }
    }
you want to verify the logic that is executed on a good form submission and the logic that is executed on a duplicate submission. Testing the bad submission is simple. Just invoke the controller:

    import grails.test.mixin.TestFor
    import spock.lang.Specification@TestFor(SimpleController)
    class SimpleControllerSpec extends Specification {    void 'test duplicate form submission'() {
            when:
            controller.handleForm()        then:
            response.text == 'Bad'
        }
    }
Testing the successful submission requires providing an appropriate `SynchronizerToken`:

    import grails.test.mixin.TestFor
    import spock.lang.Specificationimport org.codehaus.groovy.grails.web.servlet.mvc.SynchronizerTokensHolder@TestFor(SimpleController)
    class SimpleControllerSpec extends Specification {    void 'test valid form submission'() {
            when:
            def tokenHolder = SynchronizerTokensHolder.store(session)        params[SynchronizerTokensHolder.TOKEN_URI] = '/controller/handleForm'
            params[SynchronizerTokensHolder.TOKEN_KEY] = tokenHolder.generateToken(params[SynchronizerTokensHolder.TOKEN_URI])
            controller.handleForm()        then:
            response.text == 'Good'
        }
    }
If you test both the valid and the invalid request in the same test be sure to reset the response between executions of the controller:

    import grails.test.mixin.TestFor
    import spock.lang.Specificationimport org.codehaus.groovy.grails.web.servlet.mvc.SynchronizerTokensHolder@TestFor(SimpleController)
    class SimpleControllerSpec extends Specification {    void 'test form submission'() {
            when:
            controller.handleForm()        then:
            response.text == 'Bad'        when:
            response.reset()
            def tokenHolder = SynchronizerTokensHolder.store(session)        params[SynchronizerTokensHolder.TOKEN_URI] = '/controller/handleForm'
            params[SynchronizerTokensHolder.TOKEN_KEY] = tokenHolder.generateToken(params[SynchronizerTokensHolder.TOKEN_URI])
            controller.handleForm()        then:
            response.text == 'Good'
        }
    }
#### Testing File Upload You use the `GrailsMockMultipartFile` class to test file uploads. For example consider the following controller action:
    def uploadFile() {
        MultipartFile file = request.getFile("myFile")
        file.transferTo(new File("/local/disk/myFile"))
    }
To test this action you can register a `GrailsMockMultipartFile` with the request:

    import grails.test.mixin.TestFor
    import spock.lang.Specificationimport org.codehaus.groovy.grails.plugins.testing.GrailsMockMultipartFile@TestFor(SimpleController)
    class SimpleControllerSpec extends Specification {    void 'test file upload'() {
            when:
            def file = new GrailsMockMultipartFile('myFile', 'some file contents'.bytes)
            request.addFile file
            controller.uploadFile()        then:
            file.targetFileLocation.path == '/local/disk/myFile'
        }
    }
The `GrailsMockMultipartFile` constructor arguments are the name and contents of the file. It has a mock implementation of the `transferTo` method that simply records the `targetFileLocation` and doesn't write to disk. #### Testing Command Objects Special support exists for testing command object handling with the `mockCommandObject` method. For example consider the following action:

    class SimpleController {
        def handleCommand(SimpleCommand simple) {
            if(simple.hasErrors()) {
                render 'Bad'
            } else {
                render 'Good'
            }
        }
    }class SimpleCommand {
        String name    static constraints = {
            name blank: false
        }
    }
To test this you mock the command object, populate it and then validate it as follows:

    import grails.test.mixin.TestFor
    import spock.lang.Specification@TestFor(SimpleController)
    class SimpleControllerSpec extends Specification {    void 'test valid command object'() {
            given:
            def simpleCommand = new SimpleCommand(name: 'Hugh')
            simpleCommand.validate()        when:
            controller.handleCommand(simpleCommand)        then:
            response.text == 'Good'
        }    void 'test invalid command object'() {
            given:
            def simpleCommand = new SimpleCommand(name: '')
            simpleCommand.validate()        when:
            controller.handleCommand(simpleCommand)        then:
            response.text == 'Bad'
        }
    }
The testing framework also supports allowing Grails to create the command object instance automatically. To test this invoke the no-arg version of the controller action method. Grails will create an instance of the command object, perform data binding on it using the request parameters and validate the object just like it does in when the application is running. See the test below.

    import grails.test.mixin.TestFor
    import spock.lang.Specification@TestFor(SimpleController)
    class SimpleControllerSpec extends Specification {    void 'test valid command object'() {
            when:
            params.name = 'Hugh'
            controller.handleCommand()        then:
            response.text == 'Good'
        }    void 'test invalid command object'() {
            when:
            params.name = ''
            controller.handleCommand()        then:
            response.text == 'Bad'
        }
    }
#### Testing allowedMethods The unit testing environment respects the allowedMethods property in controllers. If a controller action is limited to be accessed with certain request methods, the unit test must be constructed to deal with that.

    // grails-app/controllers/com/demo/DemoController.groovypackage com.democlass DemoController {    static allowedMethods = [save: 'POST', update: 'PUT', delete: 'DELETE']    def save() {
            render 'Save was successful!'
        }    // …
    }

    // test/unit/com/demo/DemoControllerSpec.groovy
    package com.demoimport grails.test.mixin.TestFor
    import spock.lang.Specification
    import static javax.servlet.http.HttpServletResponse.*@TestFor(DemoController)
    class DemoControllerSpec extends Specification {    void "test a valid request method"() {
            when:
            request.method = 'POST'
            controller.save()        then:
            response.status == SC_OK
            response.text == 'Save was successful!'
        }    void "test an invalid request method"() {
            when:
            request.method = 'DELETE'
            controller.save()        then:
            response.status == SC_METHOD_NOT_ALLOWED
        }
    }
#### Testing Calling Tag Libraries You can test calling tag libraries using `ControllerUnitTestMixin`, although the mechanism for testing the tag called varies from tag to tag. For example to test a call to the `message` tag, add a message to the `messageSource`. Consider the following action:
    def showMessage() {
        render g.message(code: "foo.bar")
    }
This can be tested as follows:

    import grails.test.mixin.TestFor
    import spock.lang.Specification@TestFor(SimpleController)
    class SimpleControllerSpec extends Specification {    void 'test render message tag'() {
            given:
            messageSource.addMessage 'foo.bar', request.locale, 'Hello World'        when:
            controller.showMessage()        then:
            response.text == 'Hello World'
        }
    }
See unit testing tag libraries for more information. | Quick Reference (hide)