How to test dependent: :destroy with RSpec?

13,468

Solution 1

It is the right matcher, but you're not using it the correct way:

  • expect needs to receive a block containing the action to perform (in your case deleting the user)
  • change needs to receive a block that produces the numerical value that is expected to change (it can also receive an object and a symbol indicating that rspec should call the named method)

The correct way is

expect { user.destroy }.to change { Project.count }

This just asserts that the numerical value changes, but does not specify by how much. To do that, chain a call to by:

expect { user.destroy }.to change { Project.count }.by(-1)

Solution 2

You can also use shoulda matchers:

it { expect(user).to have_many(:projects).dependent(:destroy) }

https://github.com/thoughtbot/shoulda-matchers

Solution 3

This should work:

expect { user.destroy }.to change { Project.count }.by(-1)

Solution 4

You should test for the removal of the actual project.

expect(Project.all).not_to include project
Share:
13,468
Xeen
Author by

Xeen

Updated on June 18, 2022

Comments

  • Xeen
    Xeen almost 2 years

    I'd like to test my User models association has_many :projects, dependent: :destroy and have gone this far for now:

    it "destroys dependent projects" do
      user = FactoryGirl.build(:user)
      project = FactoryGirl.build(:project)
    
      user.projects << project
      user.destroy
    
      expect(Project.count).to change(-1)
    end
    

    but this gives out an error:

    Failure/Error: expect(Project.count).to change(-1)
         ArgumentError:
           `change` requires either an object and message (`change(obj, :msg)`) or a block (`change { }`). You passed an object but no message.
    

    so I presume that change isn't the right matcher, is it? Can you please tell me how I could write this test without getting that error?