Rspec - How to Test Activerecord::Recordnotfound

Test for ActiveRecord::RecordNotFound

Look in documentation for rspec-expectations#expecting-errors this:

expect(VerseSelector.select_intro_verse).to raise_exception

should be except syntax for exception must be lambda or proc:

expect { VerseSelector.select_intro_verse }.to raise_exception(ActiveRecord::RecordNotFound)

ActiveRecord::RecordNotFound rspec how to test

Assuming you are not rescuing ActiveRecord::RecordNotFound from somewhere in your controller(s), then this code will raise the error, and return a status code 404.

If you are trying to test that the exception will be raised, you need to use the matcher expect { <block_of_code> }.to raise_error <error_class>

If an exception should not be raised, then check your exception handler, because it is not being invoked.

If you want to do this without raising an ActiveRecord::RecordNotFound, you will need to switch find(id) with where(id: id).first

How to expect raise ActiveRecord::RecordNotFound rspec?

First its probably a good idea to explain that the exception matchers will only actually match uncaught exceptions. Thats because its basically just a rescue statement and rescues the exception as it bubbles up the call stack and its intended to test that a peice of code raises an exception which its up to the consumer to catch - that is an example of testing the behavior.

Testing that code raises and rescues a exception on the other hand is testing how it does its job.

def foo
raise SomeKindOfError
end

def bar
begin
raise SomeKindOfError
rescue SomeKindOfError
puts "RSpec will never catch me!"
end
end

describe "#foo" do
it "raises an exception" do
expect { foo }.to raise_exception(SomeKindOfError)
end
end

describe "#bar" do
it "rescues the exception" do
expect { bar }.to_not raise_exception(SomeKindOfError)
end
end

When you use rescue_from its basically just syntactic sugar for using an around_action callback to rescue the given exception:

class ApplicationController
around_action :handle_errors

private

def handle_errors
begin
yield
rescue SomeKindOfError
do_something
end
end
end

While RSpec did at one point have bypass_rescue for controller specs the use of controller specs is greatly discouraged by both the Rails and RSpec teams and you're really just testing the implementation instead of the behavior.

Instead you should test what the actual controller does instead of how it does it.

context 'invalid confirmation_token' do
# explicit use of subject is a code smell
before do
post signup_step5_path,
params: {
user: {
password: 'hoge',
password_confirmation: 'hoge',
confirmation_token: 'wrong_token'
}
}
end
let(:user) { User.find_by(confirmation_token: 'testtesttest') }

it 'does not update the users password' do
expect(user.valid_password?('hoge')).to be_falsy
end

it 'returns a 404 - NOT FOUND' do
expect(response).to have_http_status(:not_found)
end

# using Capybara in a feature spec is a better way to do this.
it 'renders something' do
expect(response.body).to match("Oh Noes!")
end
end

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

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

RSpec ActiveRecord::RecordNotFound

In your request, you're doing post :create, { appointment: { dentist_id: '1', ... } }, which means that params[:dentist_id] in your controller will be nil (notice how you're nesting dentist_id under appointment in your request params). To fix this, change @dentist = Dentist.find(params[:dentist_id]) in your controller action to @dentist = Dentist.find(params[:appointment][:dentist_id]), or change your request to post :create, { dentist_id: '1', appointment: { patient_id: '2' ... } }.

Update

You'll also need to create a Dentist record in your database before the test is run. To do that, add something like this to your test case:

describe 'POST #create' do
before { Dentist.create!(id: 1) }

it 'assigns a newly created appointment as @appointment' do
post :create, { dentist_id: '1', appointment: { patient_id: '2', appt_date: '2015-12-05 09:00:00' } }
...
end
end


Related Topics



Leave a reply



Submit