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.