Reputation: 12073
I have the following spec:
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
I have the following factory:
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
Tests fail with:
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 ==)
Why these objects and their attributes aren't the same and how do I properly check for object equality?
Upvotes: 0
Views: 1031
Reputation: 38645
I see the problems to be in comparison of different objects in your tests.
The following test:
it "finds record" do
page = create(:page, title: 'heyo')
Page.unscoped.where(:title => 'heyo').should == page
end
When you get to this test you already have one page
object from "has a valid factory"
test. So after this test executes you have two page objects, first with title nil
and second with title heyo
. Now when you try to match with should
in the next line your Page.unscoped.where(:title => 'heyo')
does return expected result, i.e. an array of Page
objects with title 'heyo'. You're getting an array and you're comparing the array with an Object, so that's going to fail.
Then the reason your second test "finds record with same attributes"
is failing is because you are expecting the first Page
object to be equal to last Page
object, so this is also going to fail.
So the fixes would be on the following two tests:
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
Note the use of last
in both tests.
The database_cleaner
gem is something that you might be interested in. It allows you to clean the database before each tests. Recommend looking at it.
Upvotes: 2
Reputation: 2749
The source of both errors is the same.
You are comparing one of the dates, created_at, updated_at, and they don't seem to have the same value.
Notice that the dates only go to the second when printed as strings - they might differ at a lower level than that.
Either exclude the dates from the comparison, or do a raise/inspect in the code at the site of the failure to see if the fractional seconds are differing between the two items.
Another trick you can use is to stub out Time.now/Time.new within the scope of your spec, so that you will always get a consistent result.
Normally you will stub out/abuse Time.now in a before :each block inside the context of your spec. You want to make the scope as narrow as possible because overriding that method can have all sorts of weird side effects if you aren't careful where you do it.
Upvotes: 1
Reputation: 115541
You must freeze the time in your case, use timecop for instance
Upvotes: -1