我正在编写一个简单的集成测试,我打算模拟删除失败。
控制器只是从数据库中提取记录并删除它,如下所示。
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以便在调用delete时抛出异常?我感谢任何帮助!谢谢!
答案 0 :(得分:0)
这是因为你应该使用
Item.metaClass.delete = {
throw new ValidationException("Failed!!")
}
而不是
Item.metaClass.delete = { Map params ->
throw new ValidationException("Failed!!")
}
答案 1 :(得分:0)
首先,我不认为这个问题应该被低估了。对于你想要测试你的程序如何对失败作出反应的场景,这是一个有效的问题。
这里有一些问题:
Domain.delete不会抛出validationExceptions。 ValidationExceptions也是用两个参数构造的(String msg,Errors error)。您需要向域类添加自定义错误并传入域类。再次,这对删除没有意义,因为谁需要在删除时验证对象? 不确定您正在运行的版本,但这里是2.5.1的文档(Grails 2.5.1 docs - 请参见7.3.2删除对象)
def p = Person.get(1) 尝试{ p.delete(flush:true) } catch(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来自哪里?我们是否遗漏了部分测试文件。如果没有,您的测试似乎依赖于已存在的数据。即使在集成测试中,最好以某种方式为每个测试单独创建数据,以防止测试污染和由于缺少数据而导致的测试失败。
最后,我无法在集成测试中对Domain Class本身进行正确的metaClass ...所以我建议你在测试中使用metaClass域实例。这是一个例子:
MetaClass域实例方法:
//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闭包中。 (可能在所有版本的grails中都不需要,因为这些方法在不同版本中的编译方式不同)
答案 2 :(得分:-1)
尝试使用:
Item.metaClass.'static'.delete = { Map params ->
throw new ValidationException("Failed!!")
}