Reputation: 4814
I have a custom error class ApiError
:
class ApiError < StandardError
attr_reader :message, :code, :details, :raw_json
def initialize(json)
@message = json["message"]
@code = json["code"]
@raw_json = json
super json.to_s
end
end
So I tried to write several specs to test it and no one passed. First one:
it 'raises an error' do
expect { raise ApiError, "Some error"}.to raise_error ApiError.new("Some error")
end
It failes with:
Failure/Error: expect { raise ApiError, "Some error"}.to raise_error ApiError, "Some error"
expected ApiError with "Some error", got #<ApiError: Some error> with backtrace:
# ./spec/models/...:39:in `block (4 levels) in <top (required)>'
# ./spec/models/...:39:in `block (3 levels) in <top (required)>'
And another option that surprises me a lot:
it 'raises an error 2' do
expect { raise ApiError, "Some error"}.to raise_error ApiError, "Some error"
end
It fails with:
Failure/Error: expect { raise ApiError, "Some error"}.to raise_error ApiError.new("Some error")
expected #<ApiError: Some error>, got #<ApiError: Some error> with backtrace:
# ./spec/models/...:43:in `block (4 levels) in <top (required)>'
# ./spec/models...:43:in `block (3 levels) in <top (required)>'
So, what? In the message, they seem pretty equal. Can anyone know what's the problem? And, also, what's the difference writing ApiError, "123"
and ApiError.new("123")
in spec files?
==========Upd==========
Commenting out a string with setting a message
attribute in ApiError class in case it does not overwrite a default value didn't help
class ApiError < StandardError
attr_reader :message, :code, :details, :raw_json
def initialize(json)
# @message = json["message"]
@code = json["code"]
@raw_json = json
super json.to_s
end
end
Upvotes: 6
Views: 3269
Reputation: 10420
Also useful with custom errors is checking properties, which can be achieved with having_attributes
like so:
expect { raise "oops" }
.to raise_error(
an_instance_of(RuntimeError)
.and having_attributes(message: "oops")
)
So you can use any custom attribute like raw_json
in your example.
Upvotes: 2
Reputation: 29349
message
is an attribute of StandardError
. You are overriding it and message
is nil
in your exception object. Rename your attribute and it should pass
class ApiError < StandardError
attr_reader :api_error_message, :code, :details, :raw_json
def initialize(json)
@api_error_message = json["message"]
@code = json["code"]
@raw_json = json
super json.to_s
end
end
it 'raises an error' do
expect { raise ApiError, "Some error"}.to raise_error ApiError, "Some error"
end
Update:
If you need to set message
to json["message"]
class ApiError < StandardError
attr_reader :code, :details, :raw_json
def initialize(json)
@code = json["code"]
@raw_json = json
super json["message"]
end
end
it 'raises an error' do
expect { raise ApiError, {"message" => "Some error"}}.to raise_error(ApiError, "Some error")
end
Upvotes: 5
Reputation: 5967
Since you are passing a string to ApiError.new
, your custom initialize
method ends up setting the message
of the exception to nil
:
ApiError.new("Some error").message
#=> nil
Try testing with a proper hash instead:
let(:error_hash) do
{ "message" => "oops", "code" => 42 }
end
expect { raise ApiError, error_hash }.to raise_error ApiError, "oops"
Upvotes: 0