English 中文(简体)
如何在Spock模拟特定域域域关闭
原标题:How to mock domain specific closures in Spock

我想测试一个使用 grails Email 插件发送电子邮件的圣杯控制器。 我损失了多少时间, 要模拟 < code> sendMail 关闭, 才能让互动起作用。 下面是我最新的测试代码版本 :

def  controller should send a multipart email () {
    given:  a mocked mailService 
        controller.mailService = Mock(grails.plugin.mail.MailService)
        controller.mailService.sendMail(*_) >> Mock(org.springframework.mail.MailMessage)
    when:
        controller.sendNow()
    then:
        1* _.multipart(true)
}

控制器代码看起来和你预期的相似,例如:

def mailService
def sendNow() {
    mailService.sendMail {
        multipart true
        to  [email protected] 
        from  [email protected] 
        subject  a subject 
        body  a body 
    }
}

如果我运行此测试, 我就会得到我 < code> multipulpart 互动的0个引用, 而不是1。 < code> give: 区块的第二行: 区块对我来说似乎可疑, 但如果我试着模拟一个 关闭 , 而不是 org.springframework.mail.MailMessage my test access. mail.MailMessage my access.

Edited

Aha, 几小时后再用新思维看代码, 我可以看到为什么上述代码不起作用; 为了让我抓住 < code> multipart 和其他 DSL 调用, 我将不得不嘲笑关闭本身, 而不是发送邮件方法( 由于关闭是在控制器内部定义的, 我无法做到这一点 ) 。 我也许可以做的是检查 < em> arguments 至 < code> sendMail 的方法, 以查看所有必要的信息。

最佳回答

您可以安装 < 坚固 > 绿色Mail < /坚固 > 插件, 并在 < 坚固 > 整合 < /坚固 > 测试中使用 :

绿邮插件主页:

import com.icegreen.greenmail.util.*

class GreenmailTests extends GroovyTestCase {
    def mailService
    def greenMail    

    void testSendMail() {
        Map mail = [message: hello world , from: [email protected] , to: [email protected] , subject: subject ]        

        mailService.sendMail {
            to mail.to
            from mail.from
            subject mail.subject
            body mail.message
        }        

        assertEquals(1, greenMail.getReceivedMessages().length)        
        def message = greenMail.getReceivedMessages()[0]        
        assertEquals(mail.message, GreenMailUtil.getBody(message))
        assertEquals(mail.from, GreenMailUtil.getAddressList(message.from))
        assertEquals(mail.subject, message.subject)
    }    

    void tearDown() {
        greenMail.deleteAllMessages()
    }
}

我不是Spock专家 但你应该能把这个junit测试 翻译成螺丝样式

资料来源:http://grails.org/plugin/greenmail' rel=“no follow'>http://grails.org/plugin/greenmail

Udpate, 模拟发送邮件 < /强 >, 替代

这是 Gregor 更新的答案 。 在我看来, 您必须嘲笑发送邮件方法, 并且在这个方法中有一个执行关闭时所使用的不同属性和方法的根块 。 让我们把它称为评估员 。 您将初始化关闭代表到 evaluatro, 执行关闭 。 评估员应该有这些说法 。 您看到我在这里使用更多的 junit 概念。 我不知道您可以多么容易地将它转换为 spock 概念 。 您也许能够让我们使用 spock 的行为检查设备 。

class MailVerifier {
    void multiPart(boolean v){
        //...
    }

    void to(String address){
        //...
    }

    boolean isVerified() {
        //check internal state obtained by the appropriate invocation of the methods
    }
}

def sendMail(Closure mailDefintion) {
    def evaluator = createMailVerifier()
    mailDefinition.delegate = evaluator

    mailDefinition()

    assert evaluator.verified
}
问题回答

我在Spock实现这一点的情况如下:

def messageBuilder
def bodyParams
def setup(){
    def mockMailService = new MockFor(MailService)
    mockMailService.ignore.sendMail{ callable ->
        messageBuilder = new MailMessageBuilder(null, new ConfigObject())
        messageBuilder.metaClass.body = { Map params ->
            bodyParams = params
        }
        callable.delegate = messageBuilder
        callable.resolveStrategy = Closure.DELEGATE_FIRST
        callable.call()
    }
    service.mailService = mockMailService.proxyInstance()
}

举例测试:

def "sendEmailReceipt_passesCorrectParams"(){
    when:
        def receiptItems = [] << [item: "item1", price: 100]
        service.sendEmailReceipt(receiptItems, "[email protected]")

    then:
        messageBuilder.message.to[0] == "[email protected]"
        messageBuilder.message.subject == "My subject"
        bodyParams.view == "/mailtemplates/emailReceipt"
        bodyParams.model.receiptItems == data
}

看看插件测试plexin集成测试 ,这里看: