Wednesday, February 18, 2009

Grails: reading configuration at runtime

As far as You know some basic configuration in Your Grails application is located in Config.groovy (under grails-app/conf folder). Often it is very useful to access data from it at runtime. To do that You have to use org.codehaus.groovy.grails.commons.ConfigurationHolder. For example, let's read SMTP properties from one of the previous posts.

Config.groovy:
// Some simple SMTP configuration.
grails {
mail {
host = "smtp.gmail.com"
port = 465
username = "youracount@gmail.com"
password = "yourpassword"
props = ["mail.smtp.auth":"true"]
}
}

Some service, for instance Email service:
// Using import aliasing.
import org.codehaus.groovy.grails.commons.ConfigurationHolder
as confHolder

class EmailService {

def sendEmail() {
// Reading property by name.
def username = confHolder.config.grails.mail.username
}

}

As You can see its very simple. In order to have access to Grails configuration from controllers or tags use grailsApplication: in our case grailsApplication.config.grails.mail.username. Enjoy!

Groovy import aliasing

One of the Groovy features I've discovered recently is "import aliasing". For instance, You have two classes with the same name located in two different packages. When You would like to use them together there will be conflict and to resolve it You have to use one of the mentioned classed with full package name. If someone faced such situation You know how inconvenient it is. Groovy helps to solve such situation using "import aliasing": there is an opportunity to set an alias for every import in Your class. For instance, You want to use two different Calendar classes. Let's create alias for own Calendar entity:

package com.mycompany.myorganization.core.service

import java.util.Calendar
import com.mycompany.myorganization.core.domain.Calendar
as MyCalendar

// Some other imports.

class UserService {
// Using both Calendars.
// Exampe of using own Calendar entity:
// MyCalendar myCalendar = new MyCalendar()

}

Another situation when You can use aliasing is long package names.
That's all. Enjoy it!

Monday, February 16, 2009

Unit testing: testing controller using Testing Plugin

In previous posts (Unit testing: testing domain entity using Testing Plugin and Unit testing: testing service in 3 different ways (part III)) we covered how to write unit test for domain entity and for simple service using Grails Testing Plugin. In this post I would like to show You how to write a simple unit test for controller using special mock*() function and special unit test case - mockController() and ControllerUnitTestCase. Suppose that we have simple User controller. In our example we will test update_account_information method. Let's have a look in details:

class UserController {

// Controller uses user service
// by dynamic injection.

def userService

def update_account_information = {
User user = userService.retrieveUserById(
session.user.id)
user.email = params.email
user.firstName = params.firstName
user.lastName = params.lastName

try {
userService.saveUser(user)

render(view: "profile",
model: [user: user,
accountInformationUpdateMessageCode:
"User.account.information.updated"
])
}
catch (InvalidUserException e) {
render(view: "profile",
model: [user: user])
}
}

// Some other methods.

}


As You can see - nothing complicated. Let's create a simple unit test using Grails Testing Plugin:

class UserControllerTests extends ControllerUnitTestCase {

def controller

UserControllerTests() {
// Will test User controller class.
// Do not forget to call super method at first.
// It will create test for specific controller.

super(UserController)
}

void setUp() {
// Do not forget to call super method at first.
super.setUp()

// You have to initialize controller manually,
// There is no dynamic injection.

controller = new UserController()

// Initialise the user service.
def userService = new UserService()

controller.userService = userService
}

void testUpdateAccountInformationSuccess() {
// Mocking domain classes.
def user = new User(id: 1L,
email: "taras.matyashovsky@gmail.com",
firstName: "Taras", lastName: "Matyashovsky",
password: "some hash")
mockDomain(User, [user])

// Putting user into session.
controller.session.user = user

// Setting controller's parameters.
controller.params.email =
"taras.matyashovsky@gmail.com"
controller.params.firstName = "Tarasuk"
controller.params.lastName = "Matyash"

// Testing the target method.
controller.update_account_information()

// Assertions.
assertEquals "profile", renderArgs.view
assertEquals user, renderArgs.model.user
assertEquals "User.account.information.updated",
renderArgs.model.accountInformationUpdateMessageCode
}

void testUpdateAccountInformationFailure() {
// Mocking domain classes.
def user = new User(id: 1L,
email: "taras.matyashovsky@gmail.com",
firstName: "Taras",
lastName: "Matyashovsky")
mockDomain(User, [user])

// Putting user into session.
controller.session.user = user

// Passing invalid parameters.
controller.params.email = "INVALID EMAIL ADDRESS"
controller.params.firstName = "Tarasuk"
controller.params.lastName = "Matyash"

// Testing the target method.
controller.update_account_information()

assertEquals "profile", renderArgs.view
assertEquals user, renderArgs.model.user
}

}


Pay attention to few key points:
  • by using ControllerUnitTestCase the controller's render method and params property work without any work on our part. This is true of all the dynamic properties and methods of the controller: request, response, params, session, controllerName, redirect, etc. All stuff is done by Testing Plugin
  • do not forget to call super methods - this will make sure that test will mock appropriate controller class
That's all for now.