I've written the following Grails controller
class CategoryController {
def create = {
def newCategory = new CategoryCommand()
bindData(newCategory, params)
[newCategory: newCategory]
}
}
class CategoryCommand {
String name
String seoName
}
I've written this unit test to test the data binding:
class CategoryControllerTests extends ControllerUnitTestCase {
void testCreate() {
// A new ControllerCommand should be returned if invoked with no params
assertNotNull controller.create()
// If called with params, they should be bound
mockParams.name = 'snooker'
mockParams.seoName = 'snooker-loopy'
def model = controller.create()
CategoryCommand newCategory = model.newCategory
assertEquals 'snooker', newCategory.name
assertEquals 'snooker-loopy', newCategory.seoName
}
}
But I get this exception when controller.create() is invoked:
No signature of method: com.example.CategoryController.bindData() is applicable for argument types: (com.example.CategoryCommand, org.codehaus.groovy.grails.web.taglib.GroovyPageAttributes) values: [com.example.CategoryCommand@7860e7d2, [:]]
I tried running this as an integration test instead, but the result is the same.
Right...I did a bit of digging, and found this blog page which says (about half way down):
note:ControllerUnitTestCase not support some dynamic method. For instance: bindData(). Then is better use integration testing, or you can add this method to controller:
this.controller.metaClass.bindData = { obj, params ->
params.each { key, value ->
obj."$key" = value
}
}
Or, I had a look in the Grails source code, and to mock it to do the same as what Grails does, I think you'd need to do:
import org.codehaus.groovy.grails.web.metaclass.BindDynamicMethod
this.controller.metaClass.bindData = { obj, params ->
new BindDynamicMethod().invoke( delegate, BindDynamicMethod.BIND_DATA_METHOD, [ obj, params ] as Object[] ) ;
}
(I think -- Not tested it tho)
As mentioned previously, mimicking Grails by using BindDynamicMethod works. This works for me on Grails 1.3.5:
import org.codehaus.groovy.grails.web.metaclass.BindDynamicMethod
protected void setUp() {
def mc = controller.class.metaClass
def bind = new BindDynamicMethod()
mc.bindData = { Object target, Object args ->
bind.invoke(delegate, "bindData", [ target, args ] as Object[])
}
mc.bindData = { Object target, Object args, List disallowed ->
bind.invoke(delegate, "bindData", [ target, args, [ exclude: disallowed ]] as Object[])
}
mc.bindData = { Object target, Object args, List disallowed, String filter ->
bind.invoke(delegate, "bindData", [ target, args, [ exclude: disallowed ], filter ] as Object[])
}
mc.bindData = { Object target, Object args, Map includeExclude ->
bind.invoke(delegate, "bindData", [ target, args, includeExclude ] as Object[])
}
mc.bindData = { Object target, Object args, Map includeExclude, String filter ->
bind.invoke(delegate, "bindData", [ target, args, includeExclude, filter ] as Object[])
}
mc.bindData = { Object target, Object args, String filter ->
bind.invoke(delegate, "bindData", [ target, args, filter ] as Object[])
}
}
This is copied from org/codehaus/groovy/grails/plugins/web/ControllersGrailsPlugin.groovy, and so it supports all forms of bindData.
Hopefully the situation will improve with the upcoming Grails 1.4 and testing mixins.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With