我想测试使用grails电子邮件插件发送电子邮件的Grails控制器。我不知道如何模仿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 'example@example.org'
from 'me@here.com'
subject 'a subject'
body 'a body'
}
}
如果我运行此测试,我会得到multipart
互动的0次调用,而不是1. given:
块的第二行似乎对我很可疑,但如果我试图模拟{{1} 1}}而不是Closure
我的测试崩溃了。我还应该提一下控制器本身是按预期工作的(它不能等我先弄清单元测试)。
啊哈,几个小时后以新的心态看着代码,我可以看出为什么上面的代码不起作用;为了让我能够捕获org.springframework.mail.MailMessage
和其他DSL调用,我将不得不模拟闭包本身,而不是sendMail方法(我不能这样做,因为闭包是在控制器本身内部定义的)。我可能做的是检查参数到multipart
方法,看看是否有必要传递给它。
答案 0 :(得分:4)
我能够在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, "some@email.com")
then:
messageBuilder.message.to[0] == "some@email.com"
messageBuilder.message.subject == "My subject"
bodyParams.view == "/mailtemplates/emailReceipt"
bodyParams.model.receiptItems == data
}
答案 1 :(得分:3)
您可以安装 greenMail 插件,并在集成测试中使用它:
来自greenmail插件主页:
import com.icegreen.greenmail.util.*
class GreenmailTests extends GroovyTestCase {
def mailService
def greenMail
void testSendMail() {
Map mail = [message:'hello world', from:'from@piragua.com', to:'to@piragua.com', 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测试转换为spock风格。
来源:http://grails.org/plugin/greenmail
Udpate,替代模拟sendMail
这是Gregor更新的答案。在我看来,你必须模拟sendMail方法,并且在这个方法中有一个存根,它实现了闭包中使用的不同属性和方法。让我们称之为评估者。您将初始化闭包的委托给evaluateatro,并执行闭包。评估者应该有断言。你看,我在这里使用了更多的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
}
答案 2 :(得分:1)
在此处查看插件测试:plugin integration test和此处:plugin unit test。在我看来,你很难模拟所有MailService依赖项 - 构建你的邮件消息的工厂和构建器。只有在我的控制器的sendNow被调用时,我才会进行测试。
修改
我找到了this answer。根据它你可以尝试:
def 'controller should send a multipart email'() {
given: 'a mocked mailService'
def mockMailService = new Object()
def mockMessageBuilder = Mock(MessageBuilder)
mockMailService.metaClass.sendMail = { callable ->
callable.delegate = mockMessageBuilder
callable.resolveStrategy = Closure.DELEGATE_FIRST
callable.call()
}
controller.mailService = mockMailService
when:
controller.sendNow()
then:
1* mockMessageBuilder.multipart(true)
}
答案 3 :(得分:1)
def mailService = Mock(MailService)
mockMailService.metaClass.sendMail = { ... your logic ... }
controller.mailService = mailService