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.

1 comment:

  1. Hello,
    The Article on Unit testing: testing controller using Testing Plugin is very informative. It give detail information about it .Thanks for Sharing the information Unit Testing . mobile application testing

    ReplyDelete