RSpec 失败是因为它认为 ActiveRecord 对象不相等

Posted

技术标签:

【中文标题】RSpec 失败是因为它认为 ActiveRecord 对象不相等【英文标题】:RSpec's failing because it thinks ActiveRecord objects aren't equal 【发布时间】:2011-09-16 00:36:19 【问题描述】:

非常简单的规范...

@post.user.should == @user

即使两个对象除了 object_id 外在其他方面都相同,规范也会失败。如果它们的 id 相同,ActiveRecord 对象应该等于 (==)。正在使用 factory_girl 创建对象。我已经确认这两个对象都不是“.new_record?”。比较 @post.user.id 和 @user.id 有效。

更重要的是行为不一致。这些测试正在运行,但现在尽管没有任何变化,但它们仍然失败了。

Rails 3.1 rspec-2.6 factory_girl-2.0.5 factory_girl_rails-1.1.0 jruby 1.6.4 (ruby-1.9.2-p136) windows7

我通常使用 spork,但不使用 spork 也会发生这种情况。

更多细节:

ActiveRecord::Base 中出现问题的代码行如下

def ==(comparison_object)
  super ||
    comparison_object.instance_of?(self.class) &&
    id.present? &&
    comparison_object.id == id
end

具体来说,“instance_of?” check 在不应该的时候失败了。我检查了两个对象的类层次结构。但是,当我检查每个对象的 class.id 时,它们并不相等。

此外,行为取决于我运行的命令...

jruby -S bundle exec rspec spec (FAILS)
jruby -S bundle exec rspec spec\models (PASSES)
jruby -S bundle exec rspec spec\models\post_spec.rb (PASSES)

在我的环境/test.rb 文件中设置 cache_classes=true 似乎可以解决这个问题,但我认为这不是必需的。

【问题讨论】:

你在控制台试过这个吗?此外,您是否尝试过使用其他 ruby​​ 虚拟机(例如 MRI)而不是 jruby? 我在使用 MRI 时遇到了同样的问题 如何使用 FactoryGirl 创建它们? 我只使用 FactoryGirl...“user = Factory(:user)”创建用户,在规范顶部的“之前”块内。帖子是用 user.post.build 创建的(在另一个 before 块内)。在 factory.rb 中,我有一个带有我的用户属性的 Factory.define。 (*** 阻止我在 cmets 的某些地方添加 @) 你能发布整个规范吗?也许有一些令人困惑的事情正在发生。 【参考方案1】:

这最终变得非常愚蠢。问题是我在 /spec/integration 而不是 /spec/requests 中进行了集成测试。 Rspec/Rails 仅在一组特定的目录中执行加载魔法,但会从所有目录运行所有测试(导致双重加载)。

【讨论】:

【参考方案2】:

由于活动记录的工作方式,这些对象具有不同的 object_id。在你给出的例子中

@post.user.should == @user

@post.user 和@user 是内存中完全独立的对象。即使它们是同一个类的实例,并且它们具有相同的 id 字段,它们也永远不会具有相同的 object_id(显然只要 cache_classes=false)。

其他 ORM(例如数据映射器)使用身份映射来处理此问题。在 Rails 3.1 中,活动记录中有实验性的身份映射支持,但默认情况下它是禁用的。

更多信息请见identity_map.rb

【讨论】:

这不是问题。我希望他们的 object_id 会有所不同。 ActiveRecord 覆盖 == 因此如果它们具有相同的 id 属性和类,它应该返回 True。问题是虽然类是相同的(“用户”),但类本身有不同的 object_id(意味着它们已经加载了两次)

以上是关于RSpec 失败是因为它认为 ActiveRecord 对象不相等的主要内容,如果未能解决你的问题,请参考以下文章

如何为 rspec 包含/设置可见的辅助方法?

比较相等的字符串时,RSpec 期望失败

Rspec功能测试:无法访问路径

Rspec/Capybara 正在加载,循环要求被认为是有害的

RSpec2 错误代码测试

部署数据源失败,因为 JBoss 认为它​​已经存在