Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Test for destroying associated records when object is destroyed failing in rails app

Im stuck on the test in listing 10.15 of Michael Hartls ruby on rails tutorial (http://ruby.railstutorial.org/chapters/user-microposts#code-micropost_dependency_test). My user_spec.rb is as follows

require 'spec_helper'

describe User do
  before { @user = User.new(name: "Example User", email: "[email protected]",password: "foobar", password_confirmation: "foobar") }

  subject { @user }

  it { should respond_to(:name) }
  it { should respond_to(:email) }
  it { should respond_to(:password_digest) }
  it { should respond_to(:password) }
  it { should respond_to(:password_confirmation) }
  it { should respond_to(:remember_token) }
  it { should respond_to(:admin) }
  it { should respond_to(:authenticate) }
  it { should respond_to(:microposts) }

  it { should be_valid }
  it { should_not be_admin }

  describe "with admin attribute set to 'true'" do
    before do
      @user.save!
      @user.toggle!(:admin)
    end

    it { should be_admin }
  end

  describe "when name is not present" do
    before { @user.name = " " }
    it { should_not be_valid }
  end

  describe "when email is not present" do
    before { @user.email = " " }
    it { should_not be_valid }
  end

  describe "when name is too long" do
    before { @user.name = "a" * 51 }
    it { should_not be_valid }
  end

  describe "when email format is invalid" do
    it "should be invalid" do
      addresses = %w[user@foo,com user_at_foo.org example.user@foo. foo@bar_baz.com foo@bar+baz.com]
      addresses.each do |invalid_address|
        @user.email = invalid_address
        @user.should_not be_valid
      end
    end
  end

  describe "when email format is valid" do
    it "should be valid" do
      addresses = %w[[email protected] [email protected] [email protected] [email protected]]
      addresses.each do |valid_address|
        @user.email = valid_address
        @user.should be_valid
      end
    end
  end

  describe "when email address is already taken" do
    before do
      user_with_same_email = @user.dup
      user_with_same_email.email = @user.email.upcase
      user_with_same_email.save
    end

    it { should_not be_valid }
  end

  describe "when password is not present" do
    before { @user.password = @user.password_confirmation = " "}
    it { should_not be_valid }
  end

  describe "when password doesn't match confirmation" do
    before { @user.password_confirmation = "mismatch" }
    it { should_not be_valid }
  end

  describe "when password confirmation is nil" do
    before { @user.password_confirmation = nil }
    it { should_not be_valid }
  end

  describe "return value of authenticate method" do
    before { @user.save }
    let(:found_user) { User.find_by_email(@user.email) }

    describe "with valid password" do
      it { should == found_user.authenticate(@user.password) }
    end

    describe "with invalid password" do
      let(:user_for_invalid_password) { found_user.authenticate("invalid") }
      it { should_not == user_for_invalid_password }
      specify { user_for_invalid_password.should be_false }
    end
  end

  describe "with a password that's too short" do
    before { @user.password = @user.password_confirmation = "a" * 5 }
    it { should be_invalid }
  end

  describe "remember token" do
    before { @user.save }
    its(:remember_token) { should_not be_blank }
  end

  describe "micropost associations" do
    before { @user.save }
    let!(:older_micropost) do
      FactoryGirl.create(:micropost, user:@user, created_at: 1.day.ago)
    end
    let!(:newer_micropost) do
      FactoryGirl.create(:micropost, user:@user, created_at: 1.hour.ago)
    end

    it "should have the right microposts in the right order" do
      @user.microposts.should == [newer_micropost, older_micropost]
    end

    it "should destroy the associated microposts" do
      microposts = @user.microposts.dup
      @user.destroy
      microposts.should_not be_empty
      microposts.each do |micropost|
        Micropost.find_by_id(micropost.id).should be_nil
      end
    end
  end

end

When i run the tests i get the following error :

  1) User micropost associations should destroy the associated microposts
     Failure/Error: Micropost.find_by_id(micropost.id).should be_nil
       expected: nil
            got: #<Micropost id: 2, content: "Lorem ipsum", user_id: nil, created_at: "2012-12-19 09:49:24", updated_at: "2012-12-19 10:49:24">
     # ./spec/models/user_spec.rb:133:in `block (4 levels) in <top (required)>'
     # ./spec/models/user_spec.rb:132:in `each'
     # ./spec/models/user_spec.rb:132:in `block (3 levels) in <top (required)>'

In my user.rb i have added the dependent :destroy as follows, which is required for the test to pass.

has_many :microposts, dependent: :destroy

Why is the test still failing ?

Thank You

like image 813
Priyank Patel Avatar asked Dec 19 '12 13:12

Priyank Patel


People also ask

How to run test in Rails?

2.7 The Rails Test Runner Or we can run a single test file by passing the bin/rails test command the filename containing the test cases. This will run all test methods from the test case. You can also run a particular test method from the test case by providing the -n or --name flag and the test's method name.

How to delete data from db in Rails?

The standard way to delete associated data in Rails is to let ActiveRecord handle it via dependent: :destroy . In the following example, when the parent model ( author ) is deleted, all data in the dependent models will get deleted by ActiveRecord as well. There is an indexed foreign key, but no foreign key constraint.

What is unit test in Rails?

The Tests − They are test applications that produce consistent result and prove that a Rails application does what it is expected to do. Tests are developed concurrently with the actual application. The Assertion − This is a one line of code that evaluates an object (or expression) for expected results.

How to test controller in Rails?

The currently accepted way to test rails controllers is by sending http requests to your application and writing assertions about the response. Rails has ActionDispatch::IntegrationTest which provides integration tests for Minitest which is the Ruby standard library testing framework.


2 Answers

I would encourage you not to do something like:

expect { @user.destroy }.to change(User, :count).by(-1)

This only tests the any user was deleted, it does not confirm that the correct records were deleted. Instead, I would do something like this

@user.destroy
expect { @user.reload }.to raise_error ActiveRecord::RecordNotFound

This ensures the correct user was deleted.

like image 129
ianks Avatar answered Oct 04 '22 15:10

ianks


Consider testing with a more abbreviated expect .. to change test:

it "destroys the associated microposts" do
  expect { @user.destroy }.to change(Micropost, :count).by(-2)
end

Replace the -2 with whatever change value you'd expect. For example, if it deletes 1 Micropost record, then change it to -1.

like image 23
Chris Peters Avatar answered Oct 04 '22 15:10

Chris Peters