How to mock domain specific closures in Spock
email, grails, multipart, spock
Solution
You can install the greenMail plugin, and use it in an integration test:
From the greenmail plugin home page:
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()
}
}
I'm not a Spock expert but you should be able to translate this junit test to spock style.
Source: http://grails.org/plugin/greenmail
Udpate, alternative by mocking sendMail
This is an answer to Gregor's update. In my opinion, you would have to mock the sendMail method, and inside this method have an stub that implements the different properties and methods that are used in the closure. Lets call it an evaluator. The you would initialize the closure's delegate to the evaluatro, and execute the closure. The evaluator should have the assertions. You see that I'm using more junit concepts here. I don't know how easily you can translate that into spock concepts. You probably would be able to us the behaviour checking facilities of 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
}
Problem
I'd like to test a Grails controller that is sending out emails using the grails Email plugin. I'm at a loss exactly how to mock the `sendMail` closure in order for interactions to work. Here's my latest version of the test code: ``` 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) } ``` The controller code looks something like what you'd expect, e.g.: ``` def mailService def sendNow() { mailService.sendMail { multipart true to 'example@example.org' from 'me@here.com' subject 'a subject' body 'a body' } } ``` If I run this test, I get 0 invocations of my `multipart` interaction instead of 1. The second line of the `given:` block seems suspicious to me, but if I try to mock a `Closure` instead of `org.springframework.mail.MailMessage` my test crashes. I should also mention that the controller itself works as expected (it couldn't wait for me to figure out the unit tests first). Edited Aha, looking at the code with a fresh mind a few hours later, I can see why the above code does not work; in order for me to catch `multipart` and other DSL calls, I would have to mock the closure itself, not the sendMail method (and I can't do that since the closure is defined inside the controller itself). What I probably can do is check the arguments to the `sendMail` method to see everything necessary was passed into it.