【问题标题】:Overriding event closure on Grails GORM domain class for unit testing覆盖 Grails GORM 域类上的事件关闭以进行单元测试
【发布时间】:2012-12-28 19:37:06
【问题描述】:

我正在开发一个新的 Grails 项目,最近注意到 Spring Security Core 生成的 User 类中的默认约定现在通过 beforeInsert/Update 事件自动编码密码。这是一种很好的、​​干净的、干燥的编码方式,也让人不可能忘记这样做。

但是,现在在尝试编写一些使用上述 User 类的单元测试时,我发现我要么必须模拟 springSecurityService(由于编码),或者更优选(并且干净),我会只需用一个什么都不做的覆盖 beforeInsert/Update 闭包。通常在 Groovy 中,可以使用 ExpandoMetaClass 覆盖方法,唉...

User.metaClass.beforeInsert = { /* do nothing */ }  

...但我发现在创建和保存新用户时继续调用原始的 beforeInsert。这反过来又导致我的单元测试崩溃。解决这个问题并模拟服务对我来说是微不足道的,但上述应该可以工作。我错过了什么吗? GORM 的事件关闭有什么不同我没有接受的吗?

【问题讨论】:

  • 另外需要注意的是,我的测试中有一个 @Mock([User]) 注释。这可能与奇怪的行为有关,但到目前为止只是一种预感。
  • 实例上有expando方法吗? // 提问永远不会太晚 :)
  • 你为什么认为,嘲笑 springSecurityService 不是首选的方式呢?我的意思是,在考虑依赖注入时,我首先想到的事情之一就是:外部化依赖管理,因此能够为测试目的创建存根/模拟。在我看来,改变 User 的 metaClass 无论如何都不是很清楚。
  • @MarioDavid 这不是关于什么是正确的测试方法的问题,这是一个见仁见智的问题。这是一个关于为什么覆盖 beforeInsert 不起作用的问题。我只是碰巧使用上面的描述来说明问题。

标签: unit-testing grails groovy grails-orm expandometaclass


【解决方案1】:

为了提高性能,Grails 直接使用反射和缓存方法句柄来调用事件,而不是 Groovy 的元层。原因是,如果您要保存数百个域实例,如果 Grails 必须为每个事件都通过 Groovy 的元层,则会严重影响性能。

有一些方法可以解决这个问题,例如定义您自己的 User 类,根据您的测试设置的系统/环境属性禁用事件等,但目前无法通过元编程覆盖这些方法。

【讨论】:

  • 我知道这是一个老问题。有没有办法访问缓存层来覆盖该方法?
【解决方案2】:

beforeInsert 闭包实际上不仅仅是一个类似于 toString() 或 save() 的方法,它还是一个由Gorm 支持的预定义事件。重写该方法不会阻止 Gorm 触发 PreInsert 事件,这会导致原始进程。

【讨论】:

  • 我知道 beforeInsert 是一个事件(请参阅我的最后一句话),但闭包仅确定在为给定模型触发事件时 会发生什么。覆盖它应该允许人们像其他任何事情一样改变这种行为。我并不是要阻止 GORM 触发事件,而是尝试更改触发事件时发生的情况。
【解决方案3】:

如果需要,可以将beforeInsert中的代码替换成私有方法,然后重写私有方法

【讨论】:

    猜你喜欢
    • 2011-09-14
    • 1970-01-01
    • 1970-01-01
    • 2011-08-09
    • 2017-05-17
    • 1970-01-01
    • 2010-12-22
    • 2011-03-08
    • 2016-06-06
    相关资源
    最近更新 更多