【问题标题】:Grails 1.3.5 controller test nulls command objectGrails 1.3.5 控制器测试空命令对象
【发布时间】:2010-11-03 12:37:21
【问题描述】:

直接来自“The Definitive Guide to Grails (Second Edition)”的第 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”引用为空。调用action controller.login之前,cmd有效并填充,之后为null。

如何测试命令对象?

【问题讨论】:

  • [-1] 我有一部分是对的(cmd 不为空),而在其他部分我是错的。 - 不过,我已经确定、下载并更正了示例,以便它们在实际的单元测试用例中工作。 - 我期待一些参与和由此产生的反应。 - 放弃的问题。

标签: unit-testing grails controller command-objects


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    我在控制器单元测试中使用此方法为命令对象添加额外的管道:

      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"
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-01-07
      • 2020-06-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多