register
other register

Thursday, November 25, 2010

Mocking Command Object in Grails

Class PersonCommand {
  String firstname
  String lastname

  static constraints = {
    firstname(blank: false)
    lastname(blank: false)
  }
}

Class PersonController {
  def save {PersonCommand cmd ->
    if (cmd.hasErrors()) {
      ...
    }
    else {
      render (view: 'confirm', model: [person: cmd])
    }
  }
}

Create an instance of that command object and pass it to the action. Below also shows the way to pass on a map of parameters to construct the command object. This needs the help of the metaClass.

import grails.plugin.spock.ControllerSpec

Class PersonControllerSpec extends ControllerSpec {
  def 'save action' () {
    given "":
    mockCommandObject(PersonCommand)
    Map mp = [firstname: 'joe', lastname: 'blog']
    controller.metaClass.getParams { -> mp}

    when : "person form parameters are submitted"
    // This works
    // def cmd = new PersonCommand(firstname: 'joe', lastname: 'blog')

    // This works better as it allows to pass on a map of parameters
    def cmd = new PersonCommand(mp)

    // Call the action
    controller.save(cmd)

    then : "the command object should be valid"
    assert cmd.valid()

    and : "the right model and view can be retrieved"
    renderArgs.view = 'confirm'
    renderArgs.model.person.firstname == 'joe'
  }
}

Note that the mockCommandObject only works when doing controller unit test, not domain unit test.

Friday, November 19, 2010

Monday, November 15, 2010

Grails Controller Unit Test with setting params as a map

When running controller unit test. Setting the params individually like below works fine

controller.params.firstname = 'joe'
controller.params.lastname = 'blog'

However, if setting the params using a map like below:

controller.params = [firstname: 'joe', lastname: 'blog']

It would throw exceptions:

groovy.lang.ReadOnlyPropertyException: Cannot set readonly property: params for class:

As suggested by Richard Bradley and Amit Jain in Grails mailing list, there are two solutions:

With groovy meta programming:

controller.metaClass.getParams { ->
 [firstname: 'Joe', lastName: 'blog']
}

Or use the putAll on the params:

Map myParams = [firstname: 'joe', lastname: 'blog']
controller.params.putAll(myParams)

Thursday, November 11, 2010

Integration Testing Mail function with Greenmail and Spock in Grails

Just managed to do spock integration test on my mail function running on grails.

I am using grails: 1.3.5, mail:  0.9,  spock: 0.4-groovy-1.7, greenmail: 1.2.1

RegistrationService will save the person's registration record to the database and then send a confirmation email to the person.
class RegistrationService {
def registrate (def person) {
person.save(faileOnError: true)
// when using mail plugin, mailService is automatically injected so we don't have to declare it.
// also valid: mailService.sendMail
sendMail {
multipart true
subject "Hello World"
to person.emailAddress
from "sender@test.com"
body (view: '/email/confirm', model: [person: person])
}
return person
}

To make greenmail integration work, make sure the following settings in the Config.groovy test environment. Please make sure there is no real mail server setting there, and also no real mail server settings in the conf/spring/resources.xml, otherwise a real email will be sent. Bear in mind, by using greenmail plugin for integration test, there is no real mail sent.

Previously I was doing refactoring on someone else's code and got stuck on receiving real email and fail the integration test. Thanks to Mike Hugo on nabble to pinpoint this. Here comes the settings in Config.groovy test environment:

test {
  grails.mail.port = com.icegreen.greenmail.util.ServerSetupTest.SMTP.port
  grails.mail.host = "localhost"
}
The spock integration test is as below:

import grails.plugin.spock.*;
import com.icegreen.greenmail.util.*

class RegistrationServiceIntegrationSpec extends IntegrationSpec{
def greenMail

def "create registration and send email"() {
given:
def service = new RegistrationService()

when: "a user makes a valid registration" 
def person = new Person(title: 'Mr', lastName: 'joe',
firstName: 'blog', 'dateOfBirth': new Date(),
emailAddress: 'receipt@test.com'
)
assert person.validate(), true
person == service.registrate(person)

then: "the registration should be successful and the confirmation email should be sent successfully"
assert 1 == greenMail.getReceivedMessages().length

def message = greenMail.getReceivedMessages()[0]
assert "sender@test.com" == GreenMailUtil.getAddressList(message.from)
assert "Hello World" == message.subject
}
}