mrfixij
mrfixij

Reputation: 130

Unit testing a void method: verifying arguments

I'm creating a unit test for my program. I have a void method which is taking five arguments, then converting those arguments into a closure and passing it to another service to be turned into an Email and sent. The only thing I care about is the body of this email, which is stored in one of the arguments passed into this function. Is it possible to verify this argument without changing the design of my program?

I've considered using Spock style mocks, but I can't determine if I can actually mock/stub out methods in my spec-tested class or if I can only mock out dependencies.

A simplified example

Class myTestService
{
    def outsideService
    private void sendEmail (User source, String subj, String body, List to, List attachments){
       outsideService.sendMail{
           //blah blah
           subject subj
           html wrapWithDefault(body) //wrapWithDefault is a big styling document also in this function
           //blah blah
           }
       }

int send(GrailsParameterMap params, HttpServletRequest request) {
      //Parse out attachments from request and body/subject/addressee from params
      //little bit of business logic to ensure that we can send emails in our system
      sendEmail(source,
                subject,
                "$body <br /><br /> important extra information", 
                sendTo,
                attachments)

      //Send another email to the source as a receipt
      sendEmail(source,
                subject,
                "$body extra junk $receiptBody",
                source,
                attachments)
   }

}

I need to find out if the receipt is properly adding receiptBody. Given that I'm sending a closure out to outsideService, it's hard to just rip variables out of that, so I'm at a bit of a loss.

EDIT: in response to the answer below, I've inserted a spock style mock into my testing, but I don't think I have the semantics right, because value is storing null. void "#value contains #params.body"() { given:

   //def params, request, filling in all necessary values

   def value
   def mailServiceMock = Mock(MailService)
   mailServiceMock.sendMail(*_) >> {closure ->
        closure.delegate = new Expando(
            multipart:{},
            from: {},
            subject: {},
            html: {value = it}
            bcc: {}
            )
        closure()
   }
   //inform service of mock
   service.mailService = mailServiceMock

   when:
       service.send(params, request)
   then:
   println("value = $value")
   1 * mailServiceMock.sendMail(*_) // this should fail, since this should be called twice, but one thing at a time.
   value.contains(params.body)

   }

value is showing null. Any thoughts?

Upvotes: 1

Views: 1915

Answers (1)

Will
Will

Reputation: 14519

You can mock your service.

This is a very simple script which mocks outsideService to store the value received in the html method in a script var. You should go for Spock/JUnit/YouNameIt to make this tidy.

class MyTestService
{
    def outsideService
    private void sendEmail (source, String subj, String body, List to, List attachments){
       outsideService.sendMail{
           subject subj
           html "<body>$body</body>"
       }
   }
}


myTest = new MyTestService()

def body
myTest.outsideService = [sendMail: { closure ->
  closure.delegate = new Expando(
    subject: { }, //don't care
    html: { body = it }
  )
  closure()
}]

myTest.sendEmail(null, 'my subject', 'my email body', null, null) 
assert '<body>my email body</body>' == body

Upvotes: 2

Related Questions