如何测试静态常量值是否传递到MailService sendMail关闭而不需要常量上的类前缀?

时间:2011-01-01 23:05:05

标签: grails groovy closures

我的Grails Unit Test使用Expando模拟MailService并重新定义sendMail方法。原始代码使用名为EMAIL_SUBJECT的静态常量,不带前缀。但是,当我运行测试并从 Something.EMAIL_SUBJECT 中删除“Something”时。它没有通过断言说mockMailService.subject被传递了 null 如何改进测试所以“Something”。在EMAIL_SUBJECT上不需要吗?

测试代码片段:

def createMockMailService() {

    def mockMailService = new Expando()

    mockMailService.sendMail = { callable ->

        callable.delegate = mockMailService
        callable.resolveStrategy = Closure.DELEGATE_FIRST
        callable.call()
    }

    mockMailService.subject = { header -> }

    mockMailService
}

void testThis() {
    def mockMailService = createMockMailService()

    mockMailService.subject = { assert it == "value of constant"  }

    Something something = new Something()
    something.mailService = mockMailService

    something.doSomethingThatCallsMailService()
}

受测试代码:

class Something {

    static def EMAIL_SUBJECT = "value of constant"

    def mailService = new SomeMailThing()

    def doSomethingThatCallsMailService() {
            mailService.sendMail {
            subject Something.EMAIL_SUBJECT // Remove Something prefix
        }
    }

}

1 个答案:

答案 0 :(得分:2)

乍看之下,这种行为很奇怪。根本原因是DELEGATE_FIRST解析策略与委托在这种情况下作为Expando实例相结合。 DELEGATE_FIRST首先在委托中查找EMAIL_SUBJECT属性,即mockMailService,这是一个Expando。 Expando不会在缺少的属性上抛出groovy.lang.MissingPropertyException,而是返回null。因此,该属性可以在代理上找到,而不是在所有者上进行评估(这将是您想要该属性的Something)。

您可以将解决方案策略更改为OWNER_FIRST。如果您希望坚持使用DELEGATE_FIRST因为原始mailService使用此策略调用sendMail闭包参数,则不能将Expando用于模拟邮件服务。相反,你可以使用普通的对象并在metaClass上进行元编程。

它看起来像这样:

def createMockMailService() {
   def mockMailService = new Object()
   mockMailService.metaClass.sendMail = { callable ->
      callable.delegate = mockMailService
      callable.resolveStrategy = Closure.DELEGATE_FIRST
      callable.call()
   }
   mockMailService.metaClass.subject = { header -> }
   mockMailService
}