Reputation: 21791
I want to extend and_return
method to raise exception if the argument is kind of exception.
For example
obj.stub(:meth).and_return(SomeException,"message")
This construction should raise an exception on a first call and just return the string on a second call.
How to extend rspec by this method, is there a guideline for such kind of task?
UPDATE:
General notation of this function could be:
and_return_or_raise(list of arguments or/and exceptions)
Upvotes: 0
Views: 628
Reputation: 47548
You don't need to extend anything--just use RSpec's built-in error matcher and receive counts:
class Foobar
def foo
bar
end
end
it "raises the first time, then returns a string" do
obj = Foobar.new
obj.should_receive(:bar).once.and_raise(StandardError)
obj.should_receive(:bar).once.and_return("message")
expect { obj.foo }.to raise_error(StandardError)
obj.foo.should == "message"
end
Upvotes: 1
Reputation: 6644
So, the actual business of returning the multiple values is in this method in the RSpec::Mocks::MessageExpectation
class:
def call_implementation_consecutive(*args, &block)
@value ||= call_implementation(*args, &block)
@value[[@actual_received_count, @value.size-1].min]
end
Basically, call_implementation
returns the list of expected return values that you passed to and_return
, and this method picks out the one corresponding to the current invocation (returning the last value if we call the method more times than there are values in the list).
So, to do what you're after, you could monkey-patch this method as follows:
class RSpec::Mocks::MessageExpectation
alias_method :old_call_implementation_consecutive, :call_implementation_consecutive
def call_implementation_consecutive(*args, &block)
old_call_implementation_consecutive(*args, &block).tap do |value|
raise value if value.is_a?(Class) && value < Exception
end
end
end
Upvotes: 1
Reputation: 3072
How about
stuff = [SomeException, "message"]
obj.stub(:meth).and_return do
i = stuff.shift
if i.respond_to?(:downcase)
i
else
raise i
end
end
surely not the prettiest way, but should do the job in your particular case.
Upvotes: 1