How to write RSpec for method that raises error - ruby

Hi I want to write RSpec test for the method below
Class A
def test
val = nil
raise "invalid" unless var
end
end
Can someone please help me, how can I write RSpec for #test method when val is nil

I would do:
describe A do
let(:a) { A.new }
describe '#test' do
it "raises an error" do
expect { a.test }.to raise_error("invalid")
end
end
end

Related

Preventing error from causing RSpec test failure

Suppose I have a class with methods like these:
class MyClass
...
def self.some_class_method
my_instance = MyClass.new
self.other_class_method(my_instance)
raise 'ERROR'
end
def self.other_class_method(instance)
...
end
end
And the test for it looks like this:
require 'spec_helper'
describe MyClass do
describe '.some_class_method' do
context 'testing some_class_method' do
it 'calls other_class_method' do
MyClass.should_receive(:other_class_method)
MyClass.some_class_method
end
end
end
end
The test errors out with ERROR, and if I remove the raise 'ERROR' line, the test passes. But here I want to only test whether some_class_method calls other_class_method, regardless of what happens afterwards. I could change it to expect the method to raise an error, but that's not the purpose of this particular test. Is there a better way?
You could rescue the exception in the test.
describe MyClass do
describe '.some_class_method' do
context 'testing some_class_method' do
it 'calls other_class_method' do
MyClass.should_receive(:other_class_method)
begin
MyClass.some_class_method
rescue
end
end
end
end
end
What about adding an expectation that the method is raising an error. That will even enhance your testing:
describe MyClass do
describe '.some_class_method' do
context 'testing some_class_method' do
it 'calls other_class_method' do
expect(MyClass).to receive(:other_class_method)
expect { MyClass.some_class_method }.to raise_error("ERROR")
end
end
end
end

ruby and rspec - Failing test

I am supposed to make this test pass.
describe 'new' do
it "takes a parameter and returns a HangpersonGame object" do
#hangpersonGame = HangpersonGame.new('glorp')
expect(#hangpersonGame).to be_an_instance_of(HangpersonGame)
expect(#hangpersonGame.word).to eq('glorp')
expect(#hangpersonGame.guesses).to eq('')
expect(#hangpersonGame.wrong_guesses).to eq('')
end
end
My code is this,
class HangpersonGame
attr_accessor :word
attr_accessor :guesses
attr_accessor :wrong_guesses
def initialize(word)
#word = word
#guesses = nil
#wrong_guesses = nil
end
end
The test is failing. Why? I have run the code seperately and it seems to work.

how to access instant variable with rspec

I have a class like this.
require 'net/http'
class Foo
def initialize
#error_count = 0
end
def run
result = Net::HTTP.start("google.com")
#error_count = 0 if result
rescue
#error_count += 1
end
end
And I want to count up #error_count if connection fails, so I wrote like this.
require_relative 'foo'
describe Foo do
before(:each){#foo = Foo.new}
describe "#run" do
context "when connection fails" do
before(:each){ Net::HTTP.stub(:start).and_raise }
it "should count up #error_count" do
expect{ #foo.run }.to change{ #foo.error_count }.from(0).to(1)
end
end
end
end
Then I got this error.
NoMethodError:
undefined method `error_count' for #<Foo:0x007fc8e20dcbd8 #error_count=0
How can I access instance variable with Rspec?
Edit
describe Foo do
let(:foo){ Foo.new}
describe "#run" do
context "when connection fails" do
before(:each){ Net::HTTP.stub(:start).and_raise }
it "should count up #error_count" do
expect{ foo.run }.to change{foo.send(:error_count)}.from(0).to(1)
end
end
end
end
Try #foo.send(:error_count) i guess it should work.
Update: found in docs
expect{ foo.run }.to change{foo.instance_variable_get(:#error_count)}.from(0).to(1)

Rspec: how to test for yield self

I'm using rspec 3.0.0.beta1. I have to test a method which yields self:
class Test
def initialize
yield self if block_given?
end
end
This is a succesful test:
describe Test do
context 'giving a block with one argument' do
it 'yields self'
expect { |b| described_class.new &b }.to yield_with_args described_class
end
end
end
But it only tests the object class, without testing the identity to self.
This is the closest (failing) test I wrote:
describe Test do
context 'giving a block with one argument' do
it 'yields itself'
instance = nil
expect { |b|
instance = described_class.new &b
}.to yield_with_args instance
end
end
end
It fails indeed, since that, at the time the last instance occurrence is evaluated it is nil, so it doesn't match with the instance inside the block evaluation.
The yield matchers cannot be used directly in your situation. The simplest thing to do is a variation of your second code with a different matcher later.
describe Test do
context 'giving a block with one argument' do
it 'yields itself'
yielded_instance = nil
new_instance = described_class.new { |i| yielded_instance = i }
expect(yielded_instance).to be new_instance
end
end
end

Testing if some function call method on associated object in Rspec

Assume I have some method which call another method on some object:
def initialize
#obj = SomeClass.new
end
def method
#obj.another_method
end
How can I test this with Rspec and .should_receive?
You can do it by passing obj to your class. This technique is called Dependency Injection
http://sporto.github.io/blog/2013/09/25/simple-dependency-injection/
require "rspec"
class Foo
def initialize(obj = SomeClass.new)
#obj = obj
end
def method
#obj.another_method
end
end
describe Foo do
describe "#method" do
subject { Foo.new(obj) }
let(:obj){ mock }
it "delegates to another_method" do
obj.should_receive(:another_method).and_return("correct result")
subject.method.should eq "correct result"
end
end
end
You can also do it like this but it's very bad way of testing class internals
require "rspec"
class Foo
def initialize
#obj = SomeClass.new
end
def method
#obj.another_method
end
end
describe Foo do
describe "#method" do
it "delegates to another_method" do
subject.instance_variable_get(:#obj).should_receive(:another_method).and_return("correct result")
subject.method.should eq "correct result"
end
end
describe "#method" do
it "delegates to another_method" do
SomeClass.stub_chain(:new, :another_method).and_return("correct result")
subject.method.should eq "correct result"
end
end
describe "#method" do
let(:obj) { mock(another_method: "correct result") }
it "delegates to another_method" do
SomeClass.stub(:new).and_return(obj)
obj.should_receive(:another_method)
subject.method.should eq "correct result"
end
end
end
In my code I would use depedency injection and only test output which means no #should_receive at all
require "rspec"
class Foo
attr_reader :obj
def initialize(obj = Object.new)
#obj = obj
end
def method
obj.another_method
end
end
describe Foo do
describe "#method" do
subject { Foo.new(obj)}
let(:obj){ mock }
it "delegates to another_method" do
obj.stub(:another_method).and_return("correct result")
subject.method.should eq "correct result"
end
end
end
While the dependency injection provided by the other answer is preferable, given your existing code, you would need to do something like:
describe "your class's method" do
it "should invoke another method" do
some_mock = double('SomeClass')
SomeClass.should_receive(:new).and_return(some_mock)
someMock.should_receive(:another_method).and_return('dummy_value')
expect(YourClass.new.another_method).to eq('dummy_value')
end
end
where YourClass is the class in question.
Update: Added check for returned value with nod to #Lewy

Resources