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 ControllerUn开发者_运维知识库itTestCase {
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
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...
}
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.
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.
I think this is the best way...
Put this in the test just before calling the controller method :
controller.metaClass.message = { LinkedHashMap key -> assertEquals 'please.create.business', key.code}
精彩评论