3

我被困在 Taglibs 的 Grails 3 spock 测试中的某个地方。我想测试一个 taglib 的闭包,它看起来像:

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])}"
    }
 }

我的ATagLibSpec.groovy看起来像:

@TestFor(ATagLib)
class ATagLibSpec {
def setup() {
    java.util.TimeZone.metaClass.'static'.getTimeZone  =  {a -> return null }
  }

void 'testmethod'() {
   expect:
   taglib.a()
 }  
}

我在运行测试用例时遇到的异常是: 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)

有人可以在这里指出,上述预填充getTimeZone的方式有什么问题。

4

2 回答 2

2

最好不要使用元编程,而是将 TimezoneFactoryService 注入您的 taglib。根据我的经验,必须在测试中进行元编程是代码异味的一种表现:您的代码使用静态方法来实例化对象,而不是依赖注入。

您的代码可能如下所示:

Closure a = {attrs->
java.util.TimeZone utc = timezoneFactoryService.getTimeZone(FraudnetConstants.TIMEZONE_UTC)
}

这将允许您通过使用常规 Spock Mock 以更方便的方式在您的规范中模拟您的工厂服务。

@TestFor(ATagLib)
class ATagLibSpec {
def setup() {
   taglib.timezoneFactoryService=Stub(TimezoneFactoryService) {
      getTimeZone(_) >> null
   }
  }
void 'testmethod'() {
   expect:
   taglib.a()
 }  
}
于 2017-01-19T14:33:22.090 回答
1

如果您仍想使用元编程,请注意方法的签名必须完全匹配(还有参数类型),所以:

java.util.TimeZone.metaClass.'static'.getTimeZone  =  {a -> return null }

java.util.TimeZone.getTimeZone("America/Los_Angeles")

此代码将获取美国/洛杉矶的时区,但是

java.util.TimeZone.metaClass.'static'.getTimeZone  =  {String a -> return null }

java.util.TimeZone.getTimeZone("America/Los_Angeles")

这个将返回 null 因为我们已经通过元编程正确地修改了方法。

另请注意,您必须使用注入的变量tagLib而不是taglib

于 2017-01-20T10:53:50.433 回答