Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: 14ae958db7
Fetching contributors…

Cannot retrieve contributors at this time

226 lines (188 sloc) 7.496 kb
require 'spec_helper'
describe "and_call_original" do
context "on a partial mock object" do
let(:klass) do
Class.new do
def meth_1
:original
end
def meth_2(x)
yield x, :additional_yielded_arg
end
def self.new_instance
new
end
end
end
let(:instance) { klass.new }
it 'passes the received message through to the original method' do
instance.should_receive(:meth_1).and_call_original
expect(instance.meth_1).to eq(:original)
end
it 'passes args and blocks through to the original method' do
instance.should_receive(:meth_2).and_call_original
value = instance.meth_2(:submitted_arg) { |a, b| [a, b] }
expect(value).to eq([:submitted_arg, :additional_yielded_arg])
end
it 'works for singleton methods' do
def instance.foo; :bar; end
instance.should_receive(:foo).and_call_original
expect(instance.foo).to eq(:bar)
end
it 'works for methods added through an extended module' do
instance.extend Module.new { def foo; :bar; end }
instance.should_receive(:foo).and_call_original
expect(instance.foo).to eq(:bar)
end
it "works for method added through an extended module onto a class's ancestor" do
sub_sub_klass = Class.new(Class.new(klass))
klass.extend Module.new { def foo; :bar; end }
sub_sub_klass.should_receive(:foo).and_call_original
expect(sub_sub_klass.foo).to eq(:bar)
end
it "finds the method on the most direct ancestor even if the method " +
"is available on more distant ancestors" do
klass.extend Module.new { def foo; :klass_bar; end }
sub_klass = Class.new(klass)
sub_klass.extend Module.new { def foo; :sub_klass_bar; end }
sub_klass.should_receive(:foo).and_call_original
expect(sub_klass.foo).to eq(:sub_klass_bar)
end
context 'when using any_instance' do
it 'works for instance methods defined on the class' do
klass.any_instance.should_receive(:meth_1).and_call_original
expect(klass.new.meth_1).to eq(:original)
end
it 'works for instance methods defined on the superclass of the class' do
subclass = Class.new(klass)
subclass.any_instance.should_receive(:meth_1).and_call_original
expect(subclass.new.meth_1).to eq(:original)
end
it 'works when mocking the method on one class and calling the method on an instance of a subclass' do
klass.any_instance.should_receive(:meth_1).and_call_original
expect(Class.new(klass).new.meth_1).to eq(:original)
end
end
if RUBY_VERSION.to_f > 1.8
it 'works for class methods defined on a superclass' do
subclass = Class.new(klass)
subclass.should_receive(:new_instance).and_call_original
expect(subclass.new_instance).to be_a(subclass)
end
it 'works for class methods defined on a grandparent class' do
sub_subclass = Class.new(Class.new(klass))
sub_subclass.should_receive(:new_instance).and_call_original
expect(sub_subclass.new_instance).to be_a(sub_subclass)
end
else
it 'attempts to work for class methods defined on a superclass but ' +
'executes the method with `self` as the superclass' do
::Kernel.stub(:warn)
subclass = Class.new(klass)
subclass.should_receive(:new_instance).and_call_original
expect(subclass.new_instance).to be_an_instance_of(klass)
end
it 'prints a warning to notify users that `self` will not be correct' do
subclass = Class.new(klass)
::Kernel.should_receive(:warn).with(/may not work correctly/)
subclass.should_receive(:new_instance).and_call_original
subclass.new_instance
end
end
it 'works for class methods defined on the Class class' do
klass.should_receive(:new).and_call_original
expect(klass.new).to be_an_instance_of(klass)
end
it "works for instance methods defined on the object's class's superclass" do
subclass = Class.new(klass)
inst = subclass.new
inst.should_receive(:meth_1).and_call_original
expect(inst.meth_1).to eq(:original)
end
it 'works for aliased methods' do
klass = Class.new do
class << self
alias alternate_new new
end
end
klass.should_receive(:alternate_new).and_call_original
expect(klass.alternate_new).to be_an_instance_of(klass)
end
context 'on an object that defines method_missing' do
before do
klass.class_eval do
private
def method_missing(name, *args)
if name.to_s == "greet_jack"
"Hello, jack"
else
super
end
end
end
end
it 'works when the method_missing definition handles the message' do
instance.should_receive(:greet_jack).and_call_original
expect(instance.greet_jack).to eq("Hello, jack")
end
it 'works for an any_instance partial mock' do
klass.any_instance.should_receive(:greet_jack).and_call_original
expect(instance.greet_jack).to eq("Hello, jack")
end
it 'raises an error for an unhandled message for an any_instance partial mock' do
klass.any_instance.should_receive(:not_a_handled_message).and_call_original
expect {
instance.not_a_handled_message
}.to raise_error(NameError, /not_a_handled_message/)
end
it 'raises an error on invocation if method_missing does not handle the message' do
instance.should_receive(:not_a_handled_message).and_call_original
# Note: it should raise a NoMethodError (and usually does), but
# due to a weird rspec-expectations issue (see #183) it sometimes
# raises a `NameError` when a `be_xxx` predicate matcher has been
# recently used. `NameError` is the superclass of `NoMethodError`
# so this example will pass regardless.
# If/when we solve the rspec-expectations issue, this can (and should)
# be changed to `NoMethodError`.
expect {
instance.not_a_handled_message
}.to raise_error(NameError, /not_a_handled_message/)
end
end
end
context "on a partial mock object that overrides #method" do
let(:request_klass) do
Struct.new(:method, :url) do
def perform
:the_response
end
def self.method
:some_method
end
end
end
let(:request) { request_klass.new(:get, "http://foo.com/bar") }
it 'still works even though #method has been overriden' do
request.should_receive(:perform).and_call_original
expect(request.perform).to eq(:the_response)
end
it 'works for a singleton method' do
def request.perform
:a_response
end
request.should_receive(:perform).and_call_original
expect(request.perform).to eq(:a_response)
end
end
context "on a pure mock object" do
let(:instance) { double }
it 'raises an error even if the mock object responds to the message' do
expect(instance.to_s).to be_a(String)
mock_expectation = instance.should_receive(:to_s)
instance.to_s # to satisfy the expectation
expect {
mock_expectation.and_call_original
}.to raise_error(/and_call_original.*partial mock/i)
end
end
end
Jump to Line
Something went wrong with that request. Please try again.