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.

Original source