2013-02-28 69 views
5

使用Grails 2.1.0Grails控制器在渲染模板时测试关于模型的断言?

看来,从控制器这样做:

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

允许我这样做是为控制单元测试:

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

但是,如果我改变控制器做到这一点:

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

现在模型测试中的实例是一个空数组。我已经做了相当多的搜索,大部分解决方案似乎都是针对Grails 1的,通常涉及modelAndView对象(我的测试中不存在)或renderArgs(同上)。

我发现的唯一的解决办法是,以手动覆盖测试中的观点,这样的:

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

然后发表关于字符串断言。但是,我不喜欢这个方案,因为它:

  1. 需要测试知道模板的测试模型项的文件名
  2. 让人难以不具有良好的toString()方法
  3. 让人难以对相关模型条目进行多重断言。

当控制器呈现模板时,是否有任何方法可以更直接地从测试用例中获取模型中的条目?

+0

'controller.modelAndView.model'不存在? – 2013-02-28 17:09:36

+0

@SérgioMichels正确,'controller.modelAndView'为空。请记住,这是使用惯用的Grails 2风格,其中测试被声明为“@TestFor(WhateverController)”,测试不会扩展任何东西。我不确定modelAndView是否适用于Grails 1,或者为什么我总是看到这个建议,但它不在Grails 2的这种类型的测试中。 – Rod 2013-02-28 19:26:01

回答

9

在渲染方法的代码中挖掘一点(org.codehaus.groovy.grails.web.metaclass.RenderDynamicMethod)我可以看到modelAndView仅在渲染view时才设置。

渲染一个模板确实会返回一个null modelAndView。

要检查这种情况下的模型,我认为你可以使用Groovy metaClass。这个想法是拦截原来的方法,存储价值,然后给他打电话。

基于this question,我这个建造(未测试,可能需要调整):

@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' 

} 
+0

是的,那工作。有点令人惊讶,它需要这种欺骗。 我已经采取了你的解决方案更进一步,而不是templateModel我实际上分配在控制器实例modelAndView,使其余的代码工作就像你期望,如果它是一个视图 – Rod 2013-02-28 20:30:52

+0

嗯,你可以提出一个[JIRA](http://jira.grails.org/browse/GRAILS),要求更好地访问模板模型到您的测试。这是改进之美:) – 2013-02-28 20:37:08