I am stuck somewhere in Grails 3 spock Testing for Taglibs. I want to test a closure of taglib, which looks like:
ATagLib.groovy:
Closure a = {attrs ->
java.util.TimeZone utc = java.util.TimeZone.getTimeZone(FraudnetConstants.TIMEZONE_UTC)
if (attrs.somevar) {
out << "${g.message(code: 'some.code')} ${g.formatDate([date: attrs.date, format: "h:mma", timeZone: utc])}"
} else if (attrs.freq == SomeConstants.VAL || attrs.freq == SomeConstants.VAL) {
out << g.formatDate([date: attrs.date, format: "E '@' h:mma", timeZone: utc])
} else {
out << "${g.message(code: 'some.other.code')} ${g.formatDate([date: attrs.date, format: "h:mma", timeZone: utc])}"
}
}
My ATagLibSpec.groovy looks like:
@TestFor(ATagLib)
class ATagLibSpec {
def setup() {
java.util.TimeZone.metaClass.'static'.getTimeZone = {a -> return null }
}
void 'testmethod'() {
expect:
taglib.a()
}
}
The exception i am getting while running testcases is: java.lang.NullPointerException: Cannot invoke method getTimeZone() on null object at org.grails.plugins.web.taglib.FormatTagLib$_closure2.doCall(FormatTagLib.groovy:170) at groovy.lang.Closure.call(Closure.java:414) at org.grails.taglib.TagOutput.captureTagOutput(TagOutput.java:64) at org.grails.taglib.TagLibraryMetaUtils.methodMissingForTagLib(TagLibraryMetaUtils.groovy:138) at org.grails.taglib.NamespacedTagDispatcher.methodMissing(NamespacedTagDispatcher.groovy:59)
Can someone point here, what's wrong with the above way of prepopulating getTimeZone.
instead of using metaprogramming, it is best to inject a TimezoneFactoryService into your taglib. Having to metaprogram in a test is in my experience an indication of code smell: your code uses a static method to instantiate an object, instead of dependency injection.
Your code could look like this:
This will allow you to mock your factory service in your spec in a way more convenient way, by using a regular Spock Mock.