使用服务和插件依赖项测试自定义 Grails Taglib

Posted

技术标签:

【中文标题】使用服务和插件依赖项测试自定义 Grails Taglib【英文标题】:Testing Custom Grails Taglib with Service and Plugin Dependencies 【发布时间】:2013-06-11 09:54:06 【问题描述】:

我有一个需要调用服务方法的自定义标记库,该方法又使用Wslite plugin 发送和接收 SOAP 消息。 taglib 看起来像这样。

class myTagLib 
    def myService
    def thisTag = 
        def parametersFromService = myService.method("argument")
        out << render(template:'/myFolder/myView',
        model:parametersFromService)
    

我正在尝试为这个 taglib 构建一个测试。我的测试是这样的:

void testThisTag() 
    def appliedTagLib = applyTemplate('<thisTag attr="value" />')
    def parametersFromService = myService.method("argument")
    def renderedTemplate = render(template:'/myFolder/myView',
        model:parametersFromService)
    assertEquals appliedTagLib, renderedTemplate

我首先将其编写为单元测试。我尝试了简单的MockFor(MyService) 注释,以及mocking them in a more elaborate fashion,但是当taglib 尝试调用它时myService 对象始终为空。

鉴于此,我决定最好将其作为集成测试进行;这将使我可以访问插件和服务,没问题。

但是,applyTemplate 方法仅在您的测试类扩展 GroovyPagesTestCase 时才有效。但是,如果您这样做 that,则 render 方法不起作用,至少在集成测试中不起作用。我知道 applyTemplate 和 render do 在 taglib 的单元测试中相互配合,因为我已经以这种方式测试了其他 taglib。

我似乎在一块石头和一个坚硬的地方之间。为了访问他们调用的服务、插件和 SOAP 服务,我需要一个集成测试。要使用 applyTemplate() 方法,我需要扩展 GroovyPagesTestCase,但这会破坏渲染方法。我尝试将import grails.test.GroovyPagesTestCase 添加到我的测试类中,然后从中调用applyTemplate 方法,但这会导致缺少方法异常。

想法?

Grails 版本是 2.0.1,但如果有帮助,我可以升级到 2.2.1(我们的网站正在转换中)。

---附录----- elias 建议我可以注入一个 grails.gsp.PageRenderer 实例来获得一个有效的渲染方法。我试过构建一个:

import org.codehaus.groovy.grails.web.pages.GroovyPagesTemplateEngine
import grails.gsp.PageRenderer

...

def pageRenderer

...

void setUp() 
    context = grailsApplication.mainContext
    taglib = context.getBean(myTagLib.class.name)
    pageRenderer = new PageRenderer(new GroovyPagesTemplateEngine(context.getServletContext()))

但收到此错误:

java.lang.NullPointerException: Cannot invoke method findTemplateByPath() on null object
at grails.gsp.PageRenderer.renderViewToWriter(PageRenderer.groovy:120)
at grails.gsp.PageRenderer.render(PageRenderer.groovy:77)
at MyTagLibIntegrationTests.testThisTag(MyTagLibIntegrationTests.groovy:37)

【问题讨论】:

您不需要在setUp中初始化它,只需为实例使用正确的bean名称def groovyPageRenderer就可以了。 【参考方案1】:

几天前我也在为类似的事情苦苦挣扎,我是这样解决的:

    保持测试与集成测试相同(不需要扩展任何东西) 使用grailsApplication.mainContext.getBean 获取taglib bean 的实例 使用方法调用对其进行测试

就是这样! :)

class MyTagLibTests 
    def grailsApplication
    def taglib

    @Before
    void setUp()
        // grab the taglib instance from Spring context
        taglib = grailsApplication.mainContext.getBean(MyTagLib.class.name)
    

    @Test
    void myTestAboutThisTag() 
        def thisTagArgs = [:] // set up the arguments here
        assert 'shouldResultThis' == taglib.thisTag(thisTagArgs).toString()
    

【讨论】:

这很有帮助,但是手动定义一个要比较的字符串让我像老猛犸一样伤心。我将看看是否可以找到某种方法使渲染方法可用,以便我可以与之进行比较。 对!我认为您可以在测试中注入groovyPageRenderer 的实例,并尝试使用它的渲染方法。 ...但如果我能做到,为什么不扩展 GroovyPagesTestCase 并将 applyTemplate() 的输出与 render() 的输出进行比较?请参阅我对尝试注入 pageRenderer 的编辑。这可能只是我未能正确执行基本的依赖注入。 好吧,我认为你可以这样做,但它仍然只适用于只呈现模板的 taglib。我提供了我的方法作为标签库集成测试的更通用解决方案。 而且它非常有帮助,尤其是 groovyPageRenderer 评论,它让我走上了正轨。由于这个特定问题的目标是将 taglib 的输出与呈现的模板进行比较,因此我不能完全接受它作为答案,但我会尝试在应得的地方给予信任。 :)【参考方案2】:

所以,我最终所做的是扩展 GroovyPagesTestCase 以获得 applyTemplate,然后按照 elias 的建议注入 groovyPageRenderer。 Persnickity 注意:您必须调用注入的 PageRenderer groovyPageRenderer,以便 spring 为您完成所有适当的接线。所以我的测试类最终看起来像:

class myTaglibIntegrationTests extends GroovyPagesTestCase 
    PageRenderer groovyPageRenderer 
    def imageService
    @Test
    void testThisTag() 
        def appliedTagLib = applyTemplate('<thisTag attr="value" />')
        def parametersFromService = myService.method("argument")
        def renderedTemplate = groovyPageRenderer.render(template:'/myFolder/myView',
            model:parametersFromService)
        assertEquals appliedTagLib, renderedTemplate
    

【讨论】:

在此处查看 elias 的答案,了解另一个有用的想法,即为 taglib 进行测试,在其他情况下可能会更好地工作:***.com/a/17113855/1524502【参考方案3】:

更简洁的解决方案是使用 GroovyPageUnitTestMixin,因为它已经包含一个渲染方法。

@grails.test.mixin.TestMixin(grails.test.mixin.GroovyPageUnitTestMixin)
class myTaglibIntegrationTests 

    def myService

    @Test
    void testThisTag() 
        def appliedTagLib = applyTemplate('<thisTag attr="value" />')
        def parametersFromService = myService.method("argument")
        def renderedTemplate = render(template:'/myFolder/myView', 
                                      model:parametersFromService)
        assertEquals appliedTagLib, renderedTemplate
    

关于一些简单的 taglib 测试的好文章可以在这里找到:http://mrhaki.blogspot.com/2013/05/grails-goodness-testing-views-and.html

【讨论】:

以上是关于使用服务和插件依赖项测试自定义 Grails Taglib的主要内容,如果未能解决你的问题,请参考以下文章

Grails:使用快照依赖项离线工作

Grails 中的 Spring Oauth2 提供程序 - 依赖项

Grails 使用 Spring Security Core Plugin 测试用户角色自定义验证约束

Grails 插件中的自定义 CSS 和 JS

使用 grails 2.2.0 和资源插件找不到自定义 jquery css 图像

如何使用 grails 1.3.2 和插件 spring-security-core 1 实现自定义 FilterSecurityInterceptor?