RSpec不能正确比较对象

时间:2014-01-24 19:37:48

标签: ruby-on-rails ruby activerecord rspec factory-bot

我有以下规格:

require 'spec_helper'

describe Page do
  it "has a valid factory" do
    create(:page).should be_valid
  end

  it "is invalid without a title" do
    build(:page, title: nil).should_not be_valid
  end

  it "finds record" do
    page = create(:page, title: 'heyo')
    Page.unscoped.where(:title => 'heyo').should  == page
  end

  it "finds record with same attributes" do
    page = create(:page, title: 'heyo')
    Page.unscoped.where(:title => 'heyo').first.attributes.each do |name, val|
      expect(page[name]).to eq(val)
    end
  end
end

我有以下工厂:

model_statuses = ['published', 'draft']
FactoryGirl.define do
  factory :page do
    title         { Faker::Lorem.word + ' Page' }
    slug          { title ? title.parameterize : nil }
    intro         { Faker::Lorem.sentence 10 }
    content       { Faker::Lorem.sentences(5).join ' ' }
    status        { model_statuses.sample }
  end
end

测试失败:

Failures:

  1) Page finds record with same attributes
     Failure/Error: expect(page[name]).to eq(val)

       expected: Fri, 24 Jan 2014 23:33:47 MSK +04:00
            got: Fri, 24 Jan 2014 23:33:47 MSK +04:00

       (compared using ==)

       Diff:
     # ./spec/models/page_spec.rb:20:in `block (3 levels) in <top (required)>'
     # ./spec/models/page_spec.rb:19:in `each'
     # ./spec/models/page_spec.rb:19:in `block (2 levels) in <top (required)>'

  2) Page finds record
     Failure/Error: Page.unscoped.where(:title => 'heyo').should  == page
       expected: #<Page id: 1, slug: "heyo", title: "heyo", intro: "Sed sint et nesciunt earum libero eveniet est cupid...", content: "A sunt ab exercitationem quas ex incidunt numquam. ...", created_at: "2014-01-24 19:33:47", updated_at: "2014-01-24 19:33:47", status: "draft">
            got: [#<Page id: 1, slug: "heyo", title: "heyo", intro: "Sed sint et nesciunt earum libero eveniet est cupid...", content: "A sunt ab exercitationem quas ex incidunt numquam. ...", created_at: "2014-01-24 19:33:47", updated_at: "2014-01-24 19:33:47", status: "draft">] (using ==)

为什么这些对象及其属性不一样,如何正确检查对象是否相等?

3 个答案:

答案 0 :(得分:2)

我看到了测试中不同对象的比较问题。

以下测试:

  it "finds record" do
    page = create(:page, title: 'heyo')
    Page.unscoped.where(:title => 'heyo').should  == page
  end

当您进行此测试时,您已经从page测试中获得了一个"has a valid factory"对象。因此,在执行此测试后,您将拥有两个页面对象,首先是标题nil,第二个是标题heyo。现在,当您尝试与下一行中的should匹配时,Page.unscoped.where(:title => 'heyo')会返回预期结果,即标题为“heyo”的Page个数组。你得到一个数组,你正在将数组与一个对象进行比较,这样就会失败。

然后你的第二个测试"finds record with same attributes"失败的原因是因为你期望第一个Page对象等于最后Page个对象,所以这也将失败。

所以修复将在以下两个测试中进行:

  it "finds record" do
    page = create(:page, title: 'heyo')
    Page.unscoped.where(:title => 'heyo').last.should  == page
  end

  it "finds record with same attributes" do
    page = create(:page, title: 'heyo')
    Page.unscoped.where(:title => 'heyo').last.attributes.each do |name, val|
      expect(page[name]).to eq(val)
    end
  end

请注意在两个测试中使用last

database_cleaner gem是您可能感兴趣的东西。它允许您在每次测试之前清理数据库。建议看一下。

答案 1 :(得分:1)

两个错误的来源都是一样的。

您正在比较其中一个日期,created_at,updated_at,它们似乎没有相同的值。

请注意,日期只会在以字符串形式打印时转到第二个日期 - 它们可能会在不同的级别上有所不同。

从比较中排除日期,或者在失败的站点的代码中进行加注/检查,以查看两个项目之间的小数秒数是否不同。

您可以使用的另一个技巧是在规范范围内删除Time.now/Time.new,以便始终获得一致的结果。

通常情况下,你会在一个之前存根/滥用Time.now:你的规范上下文中的每个块。你想让范围尽可能地缩小,因为如果你不小心这样做,覆盖那个方法可能会产生各种奇怪的副作用。

答案 2 :(得分:0)

您必须冻结案件中的时间,例如使用timecop