【问题标题】:overwrite gorm methods in Domain using metaclass使用元类覆盖域中的 gorm 方法
【发布时间】:2013-09-26 07:11:51
【问题描述】:

我有一个名为 User 的域类。 运行测试时,我想通过执行以下操作重新定义 User 类的 get 方法

User.metaClass.static.get = {Long id -> [username:"joe", id:id]}

但是当我调用时应用上述似乎没有影响

用户.get(2)

我可以在静态域 GORM 方法(如 get() 或 list() )中使用 metaClass 来改变它们的行为吗? 谢谢

这是我的测试用例:

@测试

void testMe(){

  User.metaClass.static.get = { id -> [username:"joe", id:id]}

  def user  = User.get(3)

  assert user.username == "joe"

}

我得到一个 NPE 无法在空对象上获取属性“用户名”

我实际上可以使用 groovy MockFor 来做到这一点

  def mockControl = new MockFor(User.class)

  mockControl.demand.get {id -> return [username:"joe"]}

  mockControl.use {

      def user = User.get(3)

      assert user.username == "joe"
  } 

【问题讨论】:

  • 有什么理由不使用可用的模拟 api?
  • @dmahapatro 你指的是什么模拟 api?
  • @Mock 用于域类。您是否专门尝试测试 User.get 是否按预期工作?
  • 这是在集成测试中。我实际上尝试放置 Mock 注释,但我会得到“Annotation @grails.test.mixin.Mock is not allowed on element METHOD”
  • 我假设真正的测试有点复杂。如果你绕过 GORM 数据库集成......你在测试什么?集成测试不允许 Mock,因为您应该在这些测试期间向数据库添加内容。

标签: grails groovy


【解决方案1】:

不要输入闭包参数。如果您在编写时使用该方法,则需要调用User.get(2L),否则您将传递一个整数并且签名不匹配。如果您将get 定义为

,它应该可以工作
User.metaClass.static.get = { id -> [username:"joe", id:id]}

【讨论】:

  • 你说的很有道理,因为我之前遇到过这种类型的问题,但在这种情况下,我仍然在同样的问题上运行
  • 所以,如果我执行 {Long id ->} 然后按照您的建议调用 User.get(2L) ,那将有效。为什么 {def id -> } 不起作用。
  • 注意,在旧版本的 Grails 中,像“get”这样的 GORM 方法是使用 methodMissing 动态创建的。在较新的版本中,它们中的大多数(除了动态查找器)都是使用 AST 转换编译的。您的“Long”有效的原因可能是因为您实际上并没有覆盖或使用 GORM 方法,只是您添加的方法。
  • 那么通过 AST 转换添加的方法,不属于“元类生命周期”吗?
  • 不,由 AST 转换添加的方法可以被覆盖,那些由 GORM 动态添加的方法不能。我建议如果你使用的是旧版本的 Grails,你可能无法做你想做的事。我仍然建议在集成测试期间填充您的数据库。
【解决方案2】:

尝试将以下注释添加到您的测试中

@Mock([User])

然后你可以这样做:

def userControl = mockFor(User)
userControl.demand.static.get() {Long id -> return null}

【讨论】:

  • 由于是集成测试,@Mock注解好像不起作用
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-14
  • 1970-01-01
  • 1970-01-01
  • 2021-01-14
  • 2015-05-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多