How to Raise Runtime Error in Rspec-Rails - ruby-on-rails

I have to test a code where I am raising some errors, I tried several techniques but it failed. The structure of the class is defined below:
SchemaController:
class SchemasController < ApplicationController
def index
#get_schema = Api::AnalyticsQueryBuilderMetadataService::Schema.show
end
end
Show method under Api -> AnalyticsQueryBuilderMetadataService -> Schema.rb file:
def self.show
params = { 'limit' => 40 }
response = Api::Connection.initiate_request('entities', params)
if response.nil?
Rails.logger.error 'Data not found for ClientId '
raise 'Data not found'
else
get_schema(response)
end
end
Rspec test I wrote for schema_spec.rb:
require 'rails_helper'
require 'spec_helper'
RSpec.describe Api::AnalyticsQueryBuilderMetadataService::Schema do
describe 'GET all schema' do
before do
# allow_any_instance_of(SchemasController).to receive(:connection).and_return({})
#binding.pry
allow(Api::Connection).to receive(:initiate_request).and_return(nil)
end
context 'When no json body is passed' do
it 'Raises NoMethodError' do
# obj = SchemasController.new
result = Api::AnalyticsQueryBuilderMetadataService::Schema.show()
# expect {result}.to raise_error(RuntimeError)
expect{result}.to raise_error
end
end
end
end
But It is giving error as:
Failures:
1) Api::AnalyticsQueryBuilderMetadataService::Schema GET all schema When no json body is passed Raises NoMethodError
Failure/Error: raise 'Data not found'
RuntimeError:
Data not found
# ./app/lib/api/analytics_query_builder_metadata_service/schema.rb:22:in `show'
# ./spec/lib/api/analytics_query_builder_metadata_service/schema_spec.rb:17:in `block (4 levels) in <top (required)>'
Finished in 2.3 seconds (files took 5.63 seconds to load)
44 examples, 1 failure
Failed examples:
rspec ./spec/lib/api/analytics_query_builder_metadata_service/schema_spec.rb:15 # Api::AnalyticsQueryBuilderMetadataService::Schema GET all schema When no json body is passed Raises NoMethodError
Help me to solve this.

From the docs;
Use the raise_error matcher to specify that a block of code raises an
error.
It means that the code in the block should be the one raising the error, but in your case the error is being raised when you declare the result variable.
To make it work you can skip the variable declaration and pass the variable value as the expect block;
expect { Api::AnalyticsQueryBuilderMetadataService::Schema.show }
.to raise_error(StandardError, 'Data not found')

Related

How do we print response body in rspec

I am trying to write an rspec file for my meetings_controller.rb so as to check if the values returned from my database are correct.
When I go to localhost:3000/meeting.json, this is the result of my data from the database
my rspec file is trying to check if the correct values are returned.
I created a folder called controller under specs (after I have installed rspec)and have the file meeting_controller_spec.rb
require 'rails_helper'
# Change this ArticlesController to your project
RSpec.describe MeetingsController, type: :controller do
describe "GET #index" do
# check index
it "returns a success response" do
get :index
puts response.body
expect(response).to have_http_status(:ok)
end
end
end
I tried to print the response body but nothing is returning. Is there a way to do this?
(base) adam-a01:reservation adrianlee$ rspec
.
Finished in 0.0892 seconds (files took 12.15 seconds to load)
1 example, 0 failures
Btw this is my meeting_controller.rb
class MeetingsController < ApplicationController
before_action :set_meeting, only: [:show, :edit, :update, :destroy]
# GET /meetings
# GET /meetings.json
def index
#meetings = Meeting.all
#meeting = Meeting.new
end
end
Update: I also tried this method as suggested below but it didnt work still
# Change this ArticlesController to your project
RSpec.describe MeetingsController, type: :controller do
describe "GET #index" do
# check index
it "returns a success response" do
get :index
raise response.body
expect(response).to have_http_status(:ok)
end
end
end
This is the error raised
Failures:
1) MeetingsController GET #index returns a success response
Failure/Error: raise response.body
RuntimeError:
# ./spec/controllers/meeting_controller_spec.rb:10:in `block (3 levels) in <top (required)>'
If you are trying to get this value for a debugging purpose you should use byebug or pry gems.
If you choose byebug, add it to your gemfile gem 'byebug' on test environment.
run bundle install and after that you are able to use it on your tests
So replace the puts with byebug
describe "GET #index" do
# check index
it "returns a success response" do
get :index
byebug
expect(response).to have_http_status(:ok)
end
end
At the console now you are exactly there. Just type response.body and enter to print it's value.
When you are done, just type c and then enter to release the console e continue your tests.
Also check here for more information about debugging with byebug
In my case I do it like this:
require 'rails_helper'
describe SuppliersController, type: :controller do
describe 'GET /suppliers' do
let!(:access_token) { create :access_token }
let!(:admin_user_token) do
create :user_token, resource_owner: create(:admin_user)
end
context 'when the requester is an admin' do
it 'returns HTTP status 200 (OK)' do
allow(controller).to receive(:doorkeeper_token) { access_token }
#request.env['HTTP_X_USERTOKEN'] = admin_user_token.token
get :index
raise response.body.inspect ## Here is what prints the value in the console.
body = JSON.parse response.body
expect(response).to have_http_status :ok
expect(body['status']).to eq 'OK'
end
end
end
end
To run the test:
rspec spec/controllers/suppliers/suppliers_controller_index_spec.rb
And it gives me the output:
F
Failures:
1) SuppliersController GET /suppliers when the requester is an admin returns HTTP status 200 (OK)
Failure/Error: raise response.body.inspect
RuntimeError:
"{\"status\":\"OK\",\"message\":\"Your request has been processed successfully.\",\"data\":[],\"page\":{\"current_page\":1,\"prev_page\":null,\"next_page\":null,\"per_page\":25,\"total_pages\":0}}"
# ./spec/controllers/suppliers/suppliers_controller_index_spec.rb:17:in `block (4 levels) in <top (required)>'
Finished in 0.47594 seconds (files took 2.82 seconds to load)
1 example, 1 failure
Failed examples:
rspec ./spec/controllers/suppliers/suppliers_controller_index_spec.rb:11 # SuppliersController GET /suppliers when the requester is an admin returns HTTP status 200 (OK)
I have to say raise a runtime error to check variable value is not a good practice,maybe you should try gem 'pry' or gem 'byebug' suggested by #DR7.
Another thing you need make sure is did you run rails s and rspec in different environment?This maybe lead to they connect to separate db.

Rspec: Test an exception which is not handled

In my public method #recalculate, calling the private method1. This method throw exception 'StandardError'. I want to test this scenario, however getting an error.
Note: I don't want to handle an exception.
def recalculate
method_1
end
private
def method_1
## do some calculation
raise StandardError.new("Test")
end
Rspec Test case:
it "Test" do
expect { #product.recalculate.recalculate }.to raise_error(StandardError)
#product.recalculate
end
1) Product.Test
Failure/Error: #product.recalculate
StandardError:
Test
(required)>'
Finished in 1.39 seconds
1 example, 1 failure
According to your example, the second line #product.recalculate raises an actual exception hence the error. Assuming recalculate method is defined in #product object, this should be enough to test it.
it "Test" do
expect { #product.recalculate }.to raise_error(StandardError)
end

rspec: how to test the ensure block after raised an error

Here's my begin..rescue..ensure block. I want to write some test cases that after error is raised, the final result {} will be returned.
I am using rspec 3.3.
def external_call
result = ExternalApi.call
rescue => e
# handle the error, and re-raise
Handler.handle(e)
raise
ensure
result.presence || {}
end
I have wrote test case for the rescue part:
context 'when external api raise error' do
it 'handles the error, and re-raise' do
allow(ExternalApi).to receive(:call).and_raise(SomeError)
expect(Handler).to receive(:handle).with(e)
expect { subject.external_call }.to raise_error(SomeError)
end
end
But I am not sure how to test the ensure part after the error is re-raised.
Here's my attempt:
it 'returns {} after error raised' do
allow(ExternalApi).to receive(:call).and_raise(SomeError)
result = subject.external_call
expect(result).to eq({})
end
In this case, the test case will fail in the subject.external_call line, since it will raise error there. I am not sure how to test this cases after the error is re-raised.
When using begin/rescue/ensure block with implicit returns, ruby will return the last method to be run in the rescue block as the return value, not the ensure. If the value from the ensure block needs to be returned, it will either have to be explicitly returned, or not included in an ensure but instead moved outside of the begin/rescue block.
Below is an example which shows the difference.
class TestClass
def self.method1
raise 'an error'
rescue
'rescue block'
ensure
'ensure block'
end
def self.method2
raise 'an error'
rescue
'rescue block'
ensure
return 'ensure block'
end
def self.method3
begin
raise 'an error'
rescue
'rescue block'
end
'ensure equivalent block'
end
end
RSpec.describe TestClass do
it do
# does not work, method1 returns 'rescue block'
expect(TestClass.method1).to eql 'ensure block'
end
it do
# does work, as method2 explicitly returns 'ensure block'
expect(TestClass.method2).to eql 'ensure block'
end
it do
# does work, as method3 uses 'ensure equivalent block' as the inferred return
expect(TestClass.method3).to eql 'ensure equivalent block'
end
end

Rails tutorial, chapter 6. error test: User return value of authenticate method with invalid password should be false [duplicate]

I am running this portion of a test:
describe Dictionary do
before do
#d = Dictionary.new
end
it 'can check whether a given keyword exists' do
#d.include?('fish').should be_false
end
With this code:
class Dictionary
def initialize
#hash = {}
end
def add(new_entry)
new_entry.class == String ? #hash[new_entry] = nil : new_entry.each { |noun, definition| #hash[noun] = definition}
end
def entries
#hash
end
def keywords
#hash.keys
end
def include?(word)
if #hash.has_key?(word)
true
else
false
end
end
end
I don't know what I'm doing wrong, but my tests keep failing and saying this:
> 1) Dictionary can check whether a given keyword exists
> Failure/Error: #d.include?('fish').should be_false
> expected false to respond to `false?`
I am confused at the error since it seems to be giving the correct answer. I would really appreciate if someone could take a few minutes to tell me what's wrong with my code.
Thank you tons.
If you browse the RSpec Expectations 2.99 and RSpec Expectations 2.14 and search the section - Truthiness and existentialism, you will find
expect(actual).to be_true # passes if actual is truthy (not nil or false)
expect(actual).to be_false # passes if actual is falsy (nil or false)
# ...............
# ...
But of you browse RSpec Expectations 3.0 , the above method names got changed to -
expect(actual).to be_truthy # passes if actual is truthy (not nil or false)
expect(actual).to be true # passes if actual == true
expect(actual).to be_falsey # passes if actual is falsy (nil or false)
# ...........
#......
It seems you are in 3.0, and using the method which were exist prior to this version. Thus you were getting the error.
I put the code in my test.rb file as below :-
class Dictionary
def initialize
#hash = {}
end
def add(new_entry)
new_entry.class == String ? #hash[new_entry] = nil : new_entry.each { |noun, definition| #hash[noun] = definition}
end
def entries
#hash
end
def keywords
#hash.keys
end
def include?(word)
if #hash.has_key?(word)
true
else
false
end
end
end
And my spec/test_spec.rb file is -
require_relative "../test.rb"
describe Dictionary do
before do
#d = Dictionary.new
end
it 'can check whether a given keyword exists' do
#d.include?('fish').should be_false
end
end
Now I am running the code from my console, and it works :
arup#linux-wzza:~/Ruby> rspec -v
2.14.8
arup#linux-wzza:~/Ruby> rspec spec
.
Finished in 0.00169 seconds
1 example, 0 failures
Now I am changing the code in my spec/test_spec.rb file :-
require_relative "../test.rb"
describe Dictionary do
before do
#d = Dictionary.new
end
it 'can check whether a given keyword exists' do
#d.include?('fish').should be_falsey
end
end
and again run the test :-
arup#linux-wzza:~/Ruby> rspec -v
2.14.8
arup#linux-wzza:~/Ruby> rspec spec
F
Failures:
1) Dictionary can check whether a given keyword exists
Failure/Error: #d.include?('fish').should be_falsey
NoMethodError:
undefined method `falsey?' for false:FalseClass
# ./spec/test_spec.rb:9:in `block (2 levels) in <top (required)>'
Finished in 0.00179 seconds
1 example, 1 failure
Failed examples:
rspec ./spec/test_spec.rb:8 # Dictionary can check whether a given keyword exists
arup#linux-wzza:~/Ruby>
Now, they also mentioned in the 3.0.0.beta1 / 2013-11-07 changelog
Rename be_true and be_false to be_truthy and be_falsey. (Sam Phippen)

argument error in Ruby

I have this code
require_relative 'die'
describe Die do
describe '#initialize' do
it 'expects a single argument' do
expect(Die.instance_method(:initialize).arity).to eq 1
end
it 'raises ArgumentError if sides are < 1' do
expect { #####line 10
Die.new(-1)
}.to raise_error(ArgumentError)
expect {
Die.new(0)
}.to raise_error(ArgumentError)
end
end
I am getting the following error
> Die#initialize raises ArgumentError if sides are < 1
Failure/Error: expect {
expected ArgumentError but nothing was raised
# ./spec.rb:10:in `block (3 levels) in <top (required)>'
I have marked line 10.Any help how I can remove this error?
and this is my DIE class
class Die
def initialize(sides)
end
def num_of_sides()
end
def roll()
end
end
Put this line inside your initialize method:
raise ArgumentError if sides < 1

Resources