Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing Custom Grails Taglib with Service and Plugin Dependencies

I have a custom taglib that needs to make calls to a service method, which in turn uses the Wslite plugin to send and receive SOAP messages. The taglib looks something like this.

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

I'm trying to construct a test for this taglib. My test is something like:

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

I started by writing this as a Unit test. I tried the simple MockFor(MyService) annotation, as well as mocking them in a more elaborate fashion, but myService object was always null when the taglib tried to invoke it.

Given that, I decided it best to simply do this as an integration test; that would get me access to the plugin and service, no problemo.

However, the applyTemplate method only works if your test class extends the GroovyPagesTestCase. If you do that though, the render method doesn't work, at least not in an integration test. I know that applyTemplate and render do work alongside each other in a unit test for a taglib, as I've tested other taglibs this way.

I seem to be between a rock and a hard place. To get access to the service, plugin, and the SOAP service they invoke, I need an integration test. To use the applyTemplate() method, I need to extend the GroovyPagesTestCase, but that breaks the render method. I've tried adding import grails.test.GroovyPagesTestCase to my test class, and then invoking the applyTemplate method off of it, but that results in a missing method exception.

Thoughts?

The Grails version is 2.0.1, but I could upgrade to 2.2.1 if that would help (our site is in transition).

---Addendum----- elias suggested that I could inject an instance of grails.gsp.PageRenderer to get a working render method. I've tried constructing one:

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()))
}

But receive this error:

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)
like image 500
jonnybot Avatar asked Mar 24 '23 13:03

jonnybot


2 Answers

I was struggling with something similar some days ago, here is how I solved it:

  1. Keep the test as in integration test (don't need to extend anything)
  2. Grab the instance of the taglib bean with grailsApplication.mainContext.getBean
  3. Test it using a method call

And that's it! :)

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()
    }
}
like image 149
Elias Dorneles Avatar answered Apr 06 '23 11:04

Elias Dorneles


So, what I ultimately did was to extend the GroovyPagesTestCase in order to get applyTemplate, then inject the groovyPageRenderer as elias suggested. Persnickity note: you must call your injected PageRenderer groovyPageRenderer in order for spring to do all the appropriate wiring for you. So my test class finally looked like:

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
    }
}
like image 20
jonnybot Avatar answered Apr 06 '23 11:04

jonnybot