Reputation: 7307
I have a very simple model called Reminder
with a boolean attribute of verified
and I want to test my method update_verified
which simply sets the attribute verified
to true
. I'm using rspec and factory girl.
# reminder.rb
def update_verified
self.update(verified: true)
end
# reminder_spec.rb
describe "#update_verified" do
it "should mark the reminder.verified to true" do
reminder = build(:reminder, verified: false)
reminder.update_verified
expect(reminder.verified).to eq(true)
end
end
For some reason, when I run the test, the new value of true
for the attribute verified
is not being persisted. However, when I run the method in console, it works fine. Thoughts?
1) Reminder#update_verified should mark the reminder.verified to true
Failure/Error: expect(reminder.verified).to eq(true)
expected: true
got: false
(compared using ==)
# ./spec/models/reminder_spec.rb:46:in `block (3 levels) in <top (required)>'
Finished in 0.19193 seconds (files took 7.07 seconds to load)
Upvotes: 12
Views: 29435
Reputation: 2162
This works for me
expect do
reminder.update_verified
reminder.reload
end.to change(reminder, :verified).from(false).to(true)
Upvotes: 10
Reputation: 39
Your object is not persisted yet, when you first time call reminder.update_verified
. Instead of update, it will just create an object with assigned attributes. When you call it for a second time, it will work properly, because object is persisted. You need to change build to create and it's gonna work.
Upvotes: 1
Reputation: 998
I found this helpful to check if the method saves changes to an object in the database:
expect { reminder.update_verified }.to change(reminder, :updated_at)
Explanation
Calling self.update(verified: true)
does not only update the verified
-column, but also the updated_at
-column. We can then check for changes in the updated_at
-column to verify that changes to the object has been saved.
Upvotes: 7
Reputation: 2309
You need to call reload
on object.
And please follow rspec best practices: use let
and subject
.
describe "#update_verified" do
let(:reminder) { build(:reminder, verified: false) }
subject { reminder.update_verified }
it "should mark the reminder.verified to true" do
subject
expect(reminder.reload.verified).to eq(true)
end
end
UPDATE
The problem is in build
method. It creates new object and does not save object to DB.
Replace build
with create
method.
Upvotes: 2
Reputation: 5623
That's quite strange, but I think you should change from the build(:reminder, verified: false)
to create(:reminder, verified: false)
then use the reload
method as others have specified above.
Upvotes: 2
Reputation: 15957
You just need to reload your object:
expect(reminder.reload.verified).to eq(true)
Upvotes: 23