user1105115
user1105115

Reputation: 503

how to unit test grails' message tag

in the controller there is an action:

    def delete = {
    withDomain {
        it.delete()
        flash.message = "${message(code: 'default.deleted.message', args: [message(code: 'chocolateBar.label', default: 'ChocolateBar'), it.name])}"
        redirect action: 'list'
    }
}

which can be tested in development. while in unit test, the message(..) method throws exception ( groovy.lang.MissingMethodException: No signature of method: longtest.ChocolateBarController.message() is applicable for argument types: (java.util.LinkedHashMap) values: [[code:chocolateBar.label, default:ChocolateBar]]):

    public void testDelete() {
    controller.params.id = '3'
    controller.delete()
    assert 'list'==controller.redirectArgs.action
}

After study, a mockTagLib method should be called during setup. But found no correct class name for built-in message(..). Please help.

Upvotes: 4

Views: 1077

Answers (1)

toshi
toshi

Reputation: 2897

I've solved the problem in unit controller test. like this:

//This is inside Spock test

@Shared
ResourceBundleMessageSource messageSource = null

@Shared
Closure mockMessage = {Map map ->
    return messageSource.getMessage((String)map.code, (Object[])map.args, Locale.default)
}

def setupSpec(){
    URL url = new File('grails-app/i18n').toURI().toURL()
    messageSource = new ResourceBundleMessageSource()
    messageSource.bundleClassLoader = new URLClassLoader(url)
    messageSource.basename = 'messages'
    messageSource.setDefaultEncoding("utf-8")
}

def setup(){
    controller.metaClass.message = mockMessage
}

This code is for spock test, but main idea is also available for normal grails test.
In running phase(not test),
calling "message" in controller class results in calling "message" of ValidationTagLib class,
but they are not bind in unit test phase.
So I made almost same logic of "message" of ValidationTagLib,
and bind it(named "mockMessage") to controller.message.
With this code, you can execute "message" correctly in controller class in test.

Upvotes: 4

Related Questions