【问题标题】:how to override gorm delete method for testing?如何覆盖 gorm 删除方法进行测试?
【发布时间】:2016-11-06 09:40:49
【问题描述】:

我正在编写一个简单的集成测试,我打算在其中模拟删除失败。

控制器只需从数据库中提取记录并将其删除,如下所示。

def deleteItem(id){


    def item = Item.get(id)

    item.delete()

}

现在,我想用下面的代码模拟删除失败

void testDeleteItem_FailDeleteFlushSaveFail(){


    Item.metaClass.delete = { Map params ->

        throw new ValidationException("Failed!!")

    }



    def model = controller.deleteItem(mp.id)


    assertEquals controller.flash.message, "Sorry an error occured when deleting!!"



    GroovySystem.metaClassRegistry.removeMetaClass(Item.class)



}

但测试失败,因为方法没有被替换。即删除时不会引发异常。我猜问题出在我的元类公式中。我怎样才能使它在调用 delete 时引发异常?我很感激任何帮助!谢谢!

【问题讨论】:

    标签: grails integration-testing


    【解决方案1】:

    这是因为你应该使用

    Item.metaClass.delete = {
    
            throw new ValidationException("Failed!!")
    
        }
    

    而不是

    Item.metaClass.delete = { Map params ->
    
            throw new ValidationException("Failed!!")
    
        }
    

    【讨论】:

      【解决方案2】:

      首先,我认为这个问题不应该被否决。对于想要测试程序对失败的反应的场景来说,这是一个有效的问题。

      这里有一些问题:

      • Domain.delete 不会抛出验证异常。 ValidationExceptions 也是用两个参数构造的(String msg,Errors 错误)。您需要将自定义错误添加到您的域类并传入域类。这对于删除也没有意义,因为谁需要在删除时验证对象? 不确定您运行的是什么版本,但这里是 2.5.1 的文档(Grails 2.5.1 docs -see 7.3.2 Deleting Objects)

        def p = Person.get(1) 尝试 { p.delete(刷新:真) } 捕捉(org.springframework.dao.DataIntegrityViolationException e){ flash.message = "无法删除人员 ${p.name}" 重定向(动作:“显示”,id:p.id) }

      • 其次,删除(failOnError: true)。我不确定那有什么作用。相反,您应该在 try catch 中包围您的 delete 方法并使用 flush: true 选项。

        try{
            item.delete(flush:true)
        }catch(DataIntegrityViolationException e){
            flash.message = "Sorry an error occurred when deleting!!"
        }
        
      • 第三,mp.id 来自哪里?我们是否缺少您的测试文件的一部分。如果不是,您的测试似乎依赖于已经存在的数据。即使在集成测试中,明智的做法是以某种方式为每个测试单独创建数据,以防止测试污染和由于缺少数据而导致测试失败。

      • 最后,我无法在我的集成测试中正确地对域类本身进行元分类...所以我建议您在测试中对域实例进行元分类。这是一个例子:

      元类域实例方法:

      //creating test data
      def item = new Item(name: 'testName')
      
      def model = controller.deleteItem(item.id)
      
      item.metaClass.delete = {Map params ->
          throw new DataIntegrityViolationException('Some error message')
      }
      
      assertEquals controller.flash.message, "Sorry an error occurred when deleting!!"
      

      编辑 1 条笔记 我忘记在 metaClass 闭包中包含“Map params ->”。 (由于这些方法在各个版本中的编译方式不同,可能并非所有版本的 grails 都需要)

      【讨论】:

        【解决方案3】:

        尝试使用:

        Item.metaClass.'static'.delete = { Map params ->
            throw new ValidationException("Failed!!")
        }
        

        【讨论】:

          猜你喜欢
          • 2015-05-13
          • 1970-01-01
          • 2011-03-14
          • 2019-02-21
          • 1970-01-01
          • 2017-05-03
          • 1970-01-01
          • 2015-05-07
          • 1970-01-01
          相关资源
          最近更新 更多