Grails 1.3.5 controller test nulls命令对象

时间:2010-11-03 12:37:21

标签: unit-testing grails controller command-objects

直接来自“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有效并填充,之后为空。

如何测试命令对象?

2 个答案:

答案 0 :(得分:0)

cmd不是null ;但是,assertTrue会抛出AssertionFailedErrornull消息。提供默认消息(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"