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)
I was struggling with something similar some days ago, here is how I solved it:
grailsApplication.mainContext.getBean
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()
}
}
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
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With