Rod
Rod

Reputation: 137

Grails controller test making assertions about model when rendering a template?

Using Grails 2.1.0

It seems that doing this from a controller:

render(view: "someView", model: [modelEntry: "hello"]) 

allows me to do this in a unit test for that controller:

controller.method() 
assert model.modelEntry == "hello" 

However, if I change the controller to do this:

render(template: "someTemplate", model: [modelEntry: "hello"]) 

Now the model instance in the test is an empty array. I've done quite a bit of searching about this, and most of the solutions seem to be for Grails 1, often involving the modelAndView object (which doesn't exist in my test) or renderArgs (ditto).

The only solution I've found is to manually override the views within the test, like this:

views['_someTemplate.gsp'] = '${modelEntry}'

and then making assertions about the string. But I dislike this solution because it:

  1. requires the test knows the filename of the template
  2. makes it difficult to test model entries that don't have good toString() methods
  3. makes it difficult to make multiple assertions about related model entries.

Is there any way to more directly get at the entries in the model from a test case when the controller renders a template?

Upvotes: 6

Views: 2241

Answers (1)

user800014
user800014

Reputation:

Digging a little bit in the code of the render method (org.codehaus.groovy.grails.web.metaclass.RenderDynamicMethod) I can see that the modelAndView is setted only when you render a view.

Rendering a template will return a null modelAndView indeed.

To inspect the model in this case I think you can use the Groovy metaClass. The idea is to intercept the original method, store the value and then call him.

Based on this question, I builded this (not tested, may need adjusts):

@TestFor(MyController)
class MyControllerTests

  def templateModel

  @Test
  void inspectTemplateModel() {
    def originalMethod = MyController.metaClass.getMetaMethod('render', [Map] as Class[])
    controller.metaClass.render = { Map args ->
      templateModel = args.model
      originalMethod.invoke(delegate, args)
    }

    controller.method()
    assert templateModel.modelEntry == 'foo'

}

Upvotes: 10

Related Questions