Set a default message for a custom error class - ruby

I have created a custom error class called MyError and a separate class called MyClass that raises this error in its class method self.raiser. I have also created to rspec expectations to test that MyError is raised and that MyError prints the message my error:
class MyError < StandardError
def self.message
'my error'
end
end
class MyClass
def self.raiser
raise MyError
end
end
describe MyClass do
specify{ expect{ MyClass.raiser }.to raise_exception 'my error' }
specify{ expect{ MyClass.raiser }.to raise_exception MyError }
end
Here's what happens when I run rspec:
$ rspec spec/raise_error.rb --format documentation
MyClass
should raise Exception with "my error" (FAILED - 1)
should raise MyError
Failures:
1) MyClass should raise Exception with "my error"
Failure/Error: specify{ expect{ MyClass.raiser }.to raise_exception 'my error' }
expected Exception with "my error", got #<MyError: MyError> with backtrace:
# ./spec/raise_error.rb:9:in `raiser'
# ./spec/raise_error.rb:14:in `block (3 levels) in <top (required)>'
# ./spec/raise_error.rb:14:in `block (2 levels) in <top (required)>'
# ./spec/raise_error.rb:14:in `block (2 levels) in <top (required)>'
Finished in 0.01662 seconds (files took 0.08321 seconds to load)
2 examples, 1 failure
Failed examples:
rspec ./spec/raise_error.rb:14 # MyClass should raise Exception with "my error"
Both of these expectations should pass. got #<MyError: MyError> is bizarre and makes no sense at all. It should be got #<MyError: "my error">
Also, I do not think this is an rspec error:
2.2.1 :007 > require 'rspec'
=> true
2.2.1 :008 > require_relative 'spec/raise_error.rb'
=> true
2.2.1 :009 > MyClass.raiser
MyError: MyError

You have to defined the method message as an instance method, not the class method as you tried.
I rewrote the custom error class :
class MyError < StandardError
def message
'my error'
end
end
class MyClass
def self.raiser
raise MyError
end
end
Here is my spec file :
require_relative "../a.rb"
describe MyClass do
it 'expects the Error class message' do
expect { MyClass.raiser }.to raise_exception 'my error'
end
it 'expects the Error class name' do
expect { MyClass.raiser }.to raise_exception MyError
end
end
Lets run the spec:
[arup#Ruby]$ rspec -fd spec/a_spec.rb
MyClass
expects the Error class message
expects the Error class name
Finished in 0.00232 seconds (files took 0.16898 seconds to load)
2 examples, 0 failures

Related

Pass a ruby &block using rspec

I want to test the functionality of the method using rspec that receives anonymous block and not raise error. Below is my code:
class SP
def speak(options={},&block)
puts "speak called"
block.call()
rescue StandardError => e
puts e.inspect()
end
end
describe SP do
it "testing speak functionality not to raise error" do
sp = SP.new
sp_mock = double(sp)
expect(sp_mock).to receive(:speak).with(sp.speak{raise StandardError}).not_to raise_error
end
end
It is below throwing error
SP testing speak functionality not to raise error
Failure/Error: expect(sp).to receive(:speak).with(sp.speak{raise StandardError})
(#<SP:0x007fead2081d20>).speak(nil)
expected: 1 time with arguments: (nil)
received: 0 times
# ./test.rb:22:in `block (2 levels) in <top (required)>'
Spent a lot of time browsing articles of ruby blocks and ruby documentation but can't figure out.
It's too complicated for no reason. Did you mean this?
it "testing speak functionality not to raise error" do
sp = SP.new
expect {
sp.speak {raise StandardError}
}.to_not raise_error
end

Rspec: undefined method `StandardError' for EmeraldComponent:Module

In my gem I have the following module:
module EmeraldComponent
def self.create(full_name)
raise StandardError('Base directory for components is missing.') if base_directory_missing?
raise StandardError('An Emerald Component must have a name.') if full_name.empty?
raise StandardError('An Emerald Component must have a namespace.') if simple_name?(full_name)
write_component(full_name)
true
end
def self.write_component(full_name)
## To be implemented
end
def self.simple_name?(full_name)
vet = full_name.split('.')
vet.length == 1
end
def self.base_directory_missing?
not (File.exist?(EmeraldComponent::BASE_DIRECTORY) && File.directory?(EmeraldComponent::BASE_DIRECTORY))
end
end
And among my Rspec tests for this module I have these:
context 'create' do
it 'raises an error if the base directory for components is missing' do
expect {
EmeraldComponent.create('test.component.Name')
}.to raise_error(StandardError)
end
it 'raises an error if it receives an empty string as component name' do
expect {
EmeraldComponent.create('')
}.to raise_error(StandardError)
end
it 'raises an error if it receives a non-namespaced component name' do
expect {
EmeraldComponent.create('test')
}.to raise_error(StandardError)
end
it 'returns true if it receives a non-empty and namespaced component name' do
expect(EmeraldComponent.create('test.component.Name')).to be true
end
It happens that when I run the test all of them are passing, except for the first. This gives me the following error.
1) EmeraldComponent Methods create returns true if it receives a non-empty and namespaced component name
Failure/Error: raise StandardError('Base directory for components is missing.') if base_directory_missing?
NoMethodError:
undefined method `StandardError' for EmeraldComponent:Module
# ./lib/EmeraldComponent.rb:10:in `create'
# ./spec/EmeraldComponent_spec.rb:48:in `block (4 levels) in <top (required)>'
As you may see, it is saying that StandardError is undefined for EmeraldComponent:Module.
But StandardError does not belong to EmeraldComponent:Module!
And besides, this same StandardError is working fine for the other tests!.
I've been fighting this error for a while and then decided to post here. Any suggestions?
You should be doing StandardError.new in place or StandardError in your create method
def self.create(full_name)
raise StandardError.new('Base directory for components is missing.') if base_directory_missing?
raise StandardError.new('An Emerald Component must have a name.') if full_name.empty?
raise StandardError.new('An Emerald Component must have a namespace.') if simple_name?(full_name)
write_component(full_name)
true
end
#victorCui is correct.
Instead of raising StandardError.new(), the recommended approach is to write:
raise StandardError, "message"
See https://github.com/rubocop-hq/ruby-style-guide#exception-class-messages

Rspec validation of method definition - Failure/Error

In Rspec, testing whether an instance is able to call method x.
DockingStation.rb
class DockingStation
def release_bike
end
end
Docking_spec.rb
require_relative '../lib/DockingStation'
describe DockingStation do
before(:each) do
#dockstat = DockingStation.new
end
describe "#DockingStation" do
it "Check release method" do
expect(#dockstat).to respond_to(:release_bike)
end
end
end
Currently getting the following error message:
1) DockingStation#DockingStation Check release method
Failure/Error: expect(#dockstat).to respond_to(:release_bike)
expected #<DockingStation:0x007fa518a6da00> to respond to :release_bike
# ./spec/Docking_spec.rb:10:in `block (3 levels) in <top (required)>'
What I'm expecting is for the object #dockstat instantiated in the Docking_spec.rb to respond to the release_bike method defined in DockingStation.rb, but this is not the case.
require_relative '../DockingStation'

RSpec hits an error in code, before it is able to expect an error to be raised

This is something that I've seen before when using RSpec Rails and I believe that I know what is happening, I just don't know how I can get around it.
To me, it appears that the following test should pass. It expects an error, and an error is raised although I assume that the source of the error is what it is tripping up on.
csv_file_spec.rb
require 'spec_helper'
RSpec.describe Cleaner::CSVFile do
context 'when CSV file does not exist' do
let(:file) { Cleaner::CSVFile.new('tmp/file-does-not-exist.csv') }
it 'raises error' do
expect(file).to raise_error
end
end
end
csv_file.rb
module Cleaner
# A CSVFile is a CSV file loaded into memory. It exposes the clean method.
class CSVFile
attr_accessor :raw
def initialize(file)
#raw = File.open(file)
end
end
end
Output
1) Cleaner::CSVFile is not valid
Failure/Error: expect(Cleaner::CSVFile.new('tmp/file-does-not-exist.csv')).to raise_error
Errno::ENOENT:
No such file or directory # rb_sysopen - tmp/file-does-not-exist.csv
# ./lib/cleaner/csv_file.rb:8:in `initialize'
# ./lib/cleaner/csv_file.rb:8:in `open'
# ./lib/cleaner/csv_file.rb:8:in `initialize'
# ./spec/csv_file_spec.rb:7:in `new'
# ./spec/csv_file_spec.rb:7:in `block (2 levels) in <top (required)>'
I can see that the CSVFile object is not able to be initialized because the file does not exist and that'll be why RSpesc can't continue the test but what can I do to get around this?
I get the feeling that there is something fundamentally wrong with my approach to testing that I'm not seeing. I'd rather delegate the error to the standard File class, and not raise my own error messages as the error is verbose enough and I'd only be duplicating effort - should I be implementing my own instead?
Thanks!
For exceptions you should use block or lambda in expect syntax:
it 'raises error' do
expect{ Cleaner::CSVFile.new('tmp/file-not-exist.csv') }.to raise_error
end
You could use stubbing also :
require 'spec_helper'
RSpec.describe Cleaner::CSVFile do
context 'when CSV file does not exist' do
it 'raises error' do
allow(described_class).to receive(:new).and_raise("File not exist")
expect { described_class.new }.to raise_error("File not exist")
end
end
end
Read match message with a string.

Rspec failing on custom exception

For some reason my Rspec test if failing when I'm expecting an exception to be raised. I'm running Rspec v2.14.1, this is a custom Ruby app, not a Rails app.
Sample code:
# test.rb
class Test
class BadError < Exception ; end
end
Spec File:
# test_spec.rb
require 'spec_helper'
require 'test'
describe Test do
it 'raises an exception' do
expect( raise Test::BadError ).to raise_exception( Test::BadError )
end
end
Result:
F
Failures:
1) Test raises an exception
Failure/Error: expect( raise Test::BadError ).to raise_exception( Test::BadError )
Test::BadError:
Test::BadError
# ./spec/test_spec.rb:6:in `block (2 levels) in <top (required)>'
Finished in 0.0005 seconds
1 example, 1 failure
Not sure how to troubleshoot this either.
You need to put your code in a block so that RSpec can evaluate it, as in:
expect { raise Test::BadError }.to raise_exception( Test::BadError )
When you pass it as a parameter, the error gets raised before RSpec do anything.

Resources