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