any_instance is supported when a class overrides Object#method #181

Closed
wants to merge 1 commit into
from
Jump to file or symbol
Failed to load files and symbols.
+22 −2
Diff settings

Always

Just for now

@@ -175,7 +175,7 @@ def observe!(method_name)
backup_method!(method_name)
@klass.class_eval(<<-EOM, __FILE__, __LINE__)
def #{method_name}(*args, &blk)
- klass = self.method(:#{method_name}).owner
+ klass = ::Object.instance_method(:method).bind(self).call(:#{method_name}).owner
klass.__recorder.playback!(self, :#{method_name})
self.__send__(:#{method_name}, *args, &blk)
end
@@ -187,7 +187,7 @@ def mark_invoked!(method_name)
@klass.class_eval(<<-EOM, __FILE__, __LINE__)
def #{method_name}(*args, &blk)
method_name = :#{method_name}
- klass = self.method(:#{method_name}).owner
+ klass = ::Object.instance_method(:method).bind(self).call(:#{method_name}).owner
invoked_instance = klass.__recorder.instance_that_received(method_name)
raise RSpec::Mocks::MockExpectationError, "The message '#{method_name}' was received by \#{self.inspect} but has already been received by \#{invoked_instance}"
end
@@ -845,6 +845,26 @@ class RSpec::SampleRspecTestClass;end
end.to raise_error(RSpec::Mocks::MockExpectationError, "The message 'existing_method' was received by #{instance_two.inspect} but has already been received by #{instance_one.inspect}")
end
end
+
+ context "when a class overrides Object#method" do
+ before do
+ klass.class_eval <<-EOM
+ def method
+ "this is not awesome but does happen in real code"
+ end
+ EOM
+ end

This comment has been minimized.

@myronmarston

myronmarston Aug 26, 2012

Member

One suggestion -- this doesn't really communicate much about a real situation where #method would be overriden. Instead, you might consider doing something like:

let(:http_request_class) { Struct.new(:method, :uri) }

This communicates better (I think an HTTP request object is the main time you'd see method overriden since it's a proper term in that domain), is less code, and is a bit less "meta" (e.g. no class_eval).

@myronmarston

myronmarston Aug 26, 2012

Member

One suggestion -- this doesn't really communicate much about a real situation where #method would be overriden. Instead, you might consider doing something like:

let(:http_request_class) { Struct.new(:method, :uri) }

This communicates better (I think an HTTP request object is the main time you'd see method overriden since it's a proper term in that domain), is less code, and is a bit less "meta" (e.g. no class_eval).

This comment has been minimized.

@alindeman

alindeman Aug 26, 2012

Contributor

👍 I like it. I'll change, squash and merge.

@alindeman

alindeman Aug 26, 2012

Contributor

👍 I like it. I'll change, squash and merge.

+
+ it "stubs the method correctly" do
+ klass.any_instance.stub(:existing_method).and_return("foo")
+ klass.new.existing_method.should == "foo"
+ end
+
+ it "mocks the method correctly" do
+ klass.any_instance.should_receive(:existing_method).and_return("foo")
+ klass.new.existing_method.should == "foo"
+ end
+ end
end
end
end