Rspec: How to verify if a record has been deleted?
Asked Answered
A

4

25

I have created a simple Rspec test to verfiy if a model created has been deleted. However, the test fails because the model still exists. Can anyone provide any assistance on how to determine if the record was actually deleted?

RSpec.describe Person, type: :model do

let(:person) {
    Person.create(
      name: "Adam",
      serial_number: "1"
    )
  }
  
  it "destroys associated relationships when person destroyed" do
  person.destroy
  expect(person).to be_empty()
  end
end
Ameeameer answered 8/2, 2021 at 19:39 Comment(0)
M
39

You have two choices. You can test that:

  1. A record was removed from the database

    it "removes a record from the database" do
      expect { person.destroy }.to change { Person.count }.by(-1)
    end
    

    But that doesn't tell you which record was removed.

  2. Or that the exact record does not exist in the database anymore

    it "removes the record from the database" do
      person.destroy
      expect { person.reload }.to raise_error(ActiveRecord::RecordNotFound)
    end
    

    or

    it "removes the record from the database" do
      person.destroy
      expect(Person.exists?(person.id)).to be false
    end
    

    But that does not make sure that the record existed before.

A combination of both could be:

    it "removes a record from the database" do
      expect { person.destroy }.to change { Person.count }.by(-1)
      expect { person.reload }.to raise_error(ActiveRecord::RecordNotFound)
    end
Marola answered 8/2, 2021 at 20:13 Comment(2)
Note that the correct way to write that is expect { person.reload }.to raise_error(ActiveRecord::RecordNotFound) instead of expect(person.reload).to raise_error(ActiveRecord::RecordNotFound)Undersurface
@Undersurface Thanks for bringing this up. I fixed my answer to address your comment.Marola
K
8

I think the following is a nice way to test a specific record has been removed with one expectation, while ensuring your testing the result of the action and not just the state of your test subject.

it "removes the record from the database" do
  expect { person.destroy }.to change { Person.exists?(person.id) }.to(false)
end
Kandi answered 2/12, 2021 at 7:50 Comment(0)
T
4

When you delete a record from a database, an object still persists in memory. That's why expect(person).to be_empty() fails.

RSpec has the change matcher. ActiveRecord has the persisted? method. It returns false if a record is not persisted in a database.

it "destroys associated relationships when rtu destroyed" do
  expect { person.destroy }.to change(Person, :count).by(-1)
  expect(person.persisted?).to be_falsey
end

destroy is a method of a framework. As far as I know, you don't need to test its methods.

Tantara answered 8/2, 2021 at 19:49 Comment(6)
This is not thread-safe. If you have another test running in parallel, Person.count can be changing for other unrelated tests running at the same time.Adriatic
It can be more specific change(Person.where(name: 'Adam', serial_number: '1'), :count).by(-1)Tantara
Still not thread-safe. Even if you pin it down tight enough to be satisfactory, a year later someone's going to copy-paste your code into some other test, and now you'll have two "Adam-1" users potentially existing at the same time. (Or failing to create at the same time)Adriatic
Anyway it's one of the default ways to achieve the goal.Tantara
@DavidHempy It works if you use the default use_transactional_fixtures = true config option to run each example in a transaction.Bradford
expect(person.persisted?).to be_falsey can be changed to expect(person).not_to be_persistedMarola
C
1

You could test the behaviour like so:

expect do
  person.destroy
end.to change(person, :persisted?).to false

If you test the behaviour you get two expectations for the price of one! ie: you can assert the before and after in one spec.

Also, the reload will raise an error, you could test that (I had to do this for some associations).

expect do
  person.destroy
  person.reload
end.to raise_error ActiveRecord::RecordNotFound
Celik answered 23/11, 2023 at 3:7 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.