我的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
}
}
}
答案 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
}