直接来自“Grails的权威指南(第二版)”第104页:
void testLoginUserNotFound() {
mockRequest.method = "POST"
mockDomain(User)
MockUtils.prepareForConstraintsTests(LoginCommand)
def cmd = new LoginCommand(login:"fred", password:"letmein")
cmd.validate()
controller.login(cmd)
assertTrue cmd.hasErrors()
assertEquals "user.not.found", cmd.errors.login
assertEquals "/store/index", renderArgs.view
}
运行此测试时,它失败并显示:
junit.framework.AssertionFailedError: junit.framework.AssertionFailedError: null
...我追踪到那时“cmd”引用为null。在调用action.login之前,cmd有效并填充,之后为空。
如何测试命令对象?
答案 0 :(得分:0)
cmd
不是null
;但是,assertTrue
会抛出AssertionFailedError
个null
消息。提供默认消息(assertTrue "default message", cmd.hasErrors()
)或仅提供状态assert cmd.hasErrors()
。
所以,让我们看看为什么cmd.hasErrors()
会返回false
。 - 那是因为自定义验证器没有返回false
,而是返回一些字符串,根据“Groovy Truth”评估为true
。 (在那里,自本书出版以来,Grails API似乎已经发生了变化。)
在LoginCommand
课程中,更改
login blank:false, validator:{ val, cmd ->
if(!cmd.user)
return "user.not.found"
}
到
login blank:false, validator:{ val, cmd ->
if(!cmd.user)
return false
}
然后,错误代码将是“LoginCommand.login.validator” 如果您需要自定义错误代码,您可以add an error object自己(不返回任何内容),如下所示:
login blank:false, validator:{ val, cmd ->
if(!cmd.user)
cmd.errors.rejectValue('login', 'user.not.found')
}
P.S。:shouldn't use MockUtils
课直接,而是extend GrailsUnitTest
。另外,MockUtils.prepareForConstraintsTests(Class)
已弃用;而且,它不适合命令对象。 - 改为使用mockForConstraintsTests(Class)
方法,继承自GrailsUnitTest
。
答案 1 :(得分:0)
我在控制器单元测试中使用此方法为命令对象添加额外的管道:
private def invoke(String action) {
def types = controller."$action".parameterTypes
if (types && types.length == 1) {
Class cmdClass = types[0]
mockCommandObject(cmdClass)
def cmd = cmdClass.newInstance()
controller.params.each{ key, value ->
try{ cmd."$key" = value } catch(MissingPropertyException ex){}
}
cmd.validate()
controller."$action"(cmd)
} else {
controller."$action"()
}
}
测试如下:
setup:
controller.params.contractNum = "invalid"
when:
invoke "lookup"