Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trying to validate Groovy closure in a unit test

I'm trying to validate that this groovy closure in a class called CUTService has the correct values:

mailService.sendMail {
    to '[email protected]'
    from '[email protected]'
    subject 'Stuff'
    body 'More stuff'
}

I've looked at https://github.com/craigatk/spock-mock-cheatsheet/raw/master/spock-mock-cheatsheet.pdf, but his syntax produces an error:

1 * mailService.sendMail({ Closure c -> c.to == '[email protected]'})

groovy.lang.MissingPropertyException: No such property: to for class: com...CUTService

I've looked at Is there any way to do mock argument capturing in Spock and tried this:

1 * mailService.sendMail({closure -> captured = closure })
assertEquals '[email protected]', captured.to

which produces:

groovy.lang.MissingPropertyException: No such property: to for class: com...CUTService

I also tried this:

1 * mailService.sendMail({captured instanceof Closure })
assertEquals '[email protected]', captured.to

which produces:

Too few invocations for:
1 * mailService.sendMail({captured instanceof Closure })   (0 invocations)

...

Unmatched invocations (ordered by similarity):
1 * mailService.sendMail(com...CUTService$_theMethod_closure5@21a4c83b)

What do I need to do to get this working?

like image 286
Don Branson Avatar asked Dec 01 '25 02:12

Don Branson


1 Answers

When you write :

mailService.sendMail {
    to '[email protected]'
    from '[email protected]'
    subject 'Stuff'
    body 'More stuff'
}

In fact, you are executing the method sendMail, with a closure c. sendMail create a delegate, and call your closure with this delegate. Your closure is in reality executed as :

delegate.to('[email protected]')
delegate.from('[email protected]')
delegate.subject('Stuff')
delegate.body('More stuff')

To test this closure, you should create a mock, configure the delegate of your closure to this mock, invoke the closure, and verify the mock expectation.

As this task is not really trivial, it's better to reuse the mail plugin and create his own mail builder :

given:
  def messageBuilder = Mock(MailMessageBuilder)

when:
   // calling a service

then: 
    1 * sendMail(_) >> { Closure callable ->
      callable.delegate = messageBuilder
      callable.resolveStrategy = Closure.DELEGATE_FIRST
      callable.call(messageBuilder)
   }
   1 * messageBuilder.to("[email protected]")
   1 * messageBuilder.from("[email protected]")
like image 133
Jérémie B Avatar answered Dec 02 '25 19:12

Jérémie B



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!