Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock/stub calls to message taglib in Grails controller

I've got a Grails controller which relies on the message taglib to resolve an i18n message:

class TokenController {
def passwordReset = {
    def token = DatedToken.findById(params.id);
    if (!isValidToken(token, params)) {
        flash.message = message(code: "forgotPassword.reset.invalidToken")
        redirect controller: 'forgotPassword', action: 'index'
        return
    }
    render view:'/forgotPassword/reset', model: [token: token.token]
}
}

I've written a unit test for the controller:

class TokenControllerTests extends ControllerUnitTestCase {

void testPasswordResetInvalidTokenRedirect() {

    controller.passwordReset()
    assert...
}
}

Since the message taglib is called in the controller I get a MissingMethodException:

groovy.lang.MissingMethodException: No signature of method: TokenController.message() is applicable for argument types: (java.util.LinkedHashMap) values: [[code:forgotPassword.reset.invalidToken]]

Does anyone know the best way to get around this issue in a unit test? Ideally I would like to perform assertions on the message but right now I'd be happy if the test just ran!

Thanks

like image 880
Dave Bower Avatar asked Jan 06 '10 15:01

Dave Bower


3 Answers

You could dynamically add the missing method in your test. Not sure if this is 100% correct but something like....

void testPasswordResetInvalidTokenRedirect() {
    controller.metaClass.message = { LinkedHashMap arg1 -> return 'test message output'}
    controller.passwordReset()
    assert...
}
like image 56
Derek Avatar answered Nov 19 '22 14:11

Derek


You can wire it up using the Metaclass, something like:

void testPasswordResetInvalidTokenRedirect() {

   TokenControllerTests.metaClass.message = { Map p -> return "foo" }
   controller.passwordReset()
   assert...
}

This returns the same message always (assuming you don't really care what the value is) but you can add logic if you want, i.e. check the value of 'code' and return a corresponding string.

like image 32
Burt Beckwith Avatar answered Nov 19 '22 15:11

Burt Beckwith


As well as trying the above answers, I decided to resolve the message in the gsp and so remove the dependency on the tag lib all together.

My code for the class now looks like:

if (!isValidToken(token, params)) {
    flash.message = "forgotPassword.reset.invalidToken"

And in the gsp I have:

<g:message code="${flash.message}" args="${flash.args}" default="${flash.defaultMsg}"/>

A solution inspired by the grails docs

Of course Derek and Burt's answers work for all tag libs so are more general solutions.

like image 2
Dave Bower Avatar answered Nov 19 '22 13:11

Dave Bower