Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Ensure that any_instance expectations are properly cleaned up between…

… examples.

- Closes #52.
  • Loading branch information...
commit 7bf585190685cb22970e2318a9c75f3b7ab99e91 1 parent 1b59f2f
Sidu Ponnappa kaiwren authored dchelimsky committed
Showing with 115 additions and 56 deletions.
  1. +1 −23 lib/rspec/mocks/any_instance.rb
  2. +114 −33 spec/rspec/mocks/any_instance_spec.rb
24 lib/rspec/mocks/any_instance.rb
View
@@ -134,17 +134,8 @@ def should_receive(method_name, *args, &block)
end
def stop_observing_currently_observed_methods!
- observed_method_names.each do |method_name|
- restore_method!(method_name)
- end
- end
-
- def playback_to_uninvoked_observed_methods_with_stubs_or_expectations!(instance)
@observed_methods.each do |method_name|
- case chain = @message_chains[method_name]
- when ExpectationChain
- chain.playback!(instance) unless @played_methods[method_name]
- end
+ restore_method!(method_name)
end
end
@@ -193,13 +184,8 @@ def restore_method!(method_name)
else
remove_dummy_method!(method_name)
end
- @observed_methods.delete(method_name)
end
- def observed_method_names
- @observed_methods
- end
-
def build_alias_method_name(method_name)
"__#{method_name}_without_any_instance__".to_sym
end
@@ -253,16 +239,8 @@ def #{method_name}(*args, &blk)
end
end
- module ExpectationEnsurer
- def rspec_verify
- self.class.__recorder.playback_to_uninvoked_observed_methods_with_stubs_or_expectations!(self)
- super
- end
- end
-
def any_instance
RSpec::Mocks::space.add(self) if RSpec::Mocks::space
- self.class_eval{ include ExpectationEnsurer }
__recorder
end
147 spec/rspec/mocks/any_instance_spec.rb
View
@@ -5,12 +5,14 @@ module Mocks
describe "#any_instance" do
class CustomErrorForAnyInstanceSpec < StandardError;end
+ EXISTING_METHOD_RETURN_VALUE = Object.new
let(:klass) do
Class.new do
- def existing_method; 2; end
+ def existing_method; EXISTING_METHOD_RETURN_VALUE; end
def another_existing_method; 4; end
end
end
+ let(:existing_method_return_value){ EXISTING_METHOD_RETURN_VALUE }
context "invocation order" do
context "#stub" do
@@ -53,7 +55,21 @@ def another_existing_method; 4; end
klass.any_instance.stub(:foo)
lambda{ klass.new.bar }.should raise_error(NoMethodError)
end
-
+
+ context "behaves as 'every instance'" do
+ it "stubs every instance in the spec" do
+ klass.any_instance.stub(:foo).and_return(result = Object.new)
+ klass.new.foo.should eq(result)
+ klass.new.foo.should eq(result)
+ end
+
+ it "stubs instance created before any_instance was called" do
+ instance = klass.new
+ klass.any_instance.stub(:foo).and_return(result = Object.new)
+ instance.foo.should eq(result)
+ end
+ end
+
context "with #and_return" do
it "stubs a method that doesn't exist" do
klass.any_instance.stub(:foo).and_return(1)
@@ -178,7 +194,16 @@ class RSpec::SampleRspecTestClass;end
end.to raise_error(RSpec::Mocks::MockExpectationError, 'Exactly one instance should have received the following message(s) but didn\'t: bar, foo')
end
- context "after any one instance has received a message" do
+ it "allows expectations on instances to take priority" do
+ klass.any_instance.should_receive(:foo)
+ klass.new.foo
+
+ instance = klass.new
+ instance.should_receive(:foo).and_return(result = Object.new)
+ instance.foo.should eq(result)
+ end
+
+ context "behaves as 'exactly one instance'" do
it "passes if subsequent invocations do not receive that message" do
klass.any_instance.should_receive(:foo)
klass.new.foo
@@ -196,6 +221,27 @@ class RSpec::SampleRspecTestClass;end
end.to raise_error(RSpec::Mocks::MockExpectationError, "The message 'foo' was received by #{instance_two.inspect} but has already been received by #{instance_one.inspect}")
end
end
+
+ context "normal expectations on the class object" do
+ it "fail when unfulfilled" do
+ expect do
+ klass.any_instance.should_receive(:foo)
+ klass.should_receive(:woot)
+ klass.new.foo
+ klass.rspec_verify
+ end.to(raise_error(RSpec::Mocks::MockExpectationError) do |error|
+ error.message.should_not eq(existing_method_expectation_error_message)
+ end)
+ end
+
+
+ it "pass when expectations are met" do
+ klass.any_instance.should_receive(:foo)
+ klass.should_receive(:woot).and_return(result = Object.new)
+ klass.new.foo
+ klass.woot.should eq(result)
+ end
+ end
end
context "with an expectation is set on a method that exists" do
@@ -247,15 +293,6 @@ class RSpec::SampleRspecTestClass;end
end
end
- context "resetting" do
- it "does not interfere with expectations set on the class" do
- expect do
- klass.should_receive(:woot).and_return(3)
- klass.rspec_verify
- end.to raise_error(RSpec::Mocks::MockExpectationError)
- end
- end
-
context "message count" do
context "the 'once' constraint" do
it "passes for one invocation" do
@@ -446,39 +483,83 @@ class RSpec::SampleRspecTestClass;end
end
context "when resetting after an example" do
+ let(:space) { RSpec::Mocks::Space.new }
+
context "existing method" do
- let(:space) { RSpec::Mocks::Space.new }
-
before(:each) do
space.add(klass)
- klass.any_instance.stub(:existing_method).and_return(1)
- klass.method_defined?(:__existing_method_without_any_instance__).should be_true
end
+
+ context "with stubbing" do
+ before(:each) do
+ klass.any_instance.stub(:existing_method).and_return(1)
+ klass.method_defined?(:__existing_method_without_any_instance__).should be_true
+ end
+
+ it "restores the class to its original state after each example when no instance is created" do
+ space.reset_all
- it "restores the class to its original state after each example when no instance is created" do
- space.reset_all
+ klass.method_defined?(:__existing_method_without_any_instance__).should be_false
+ klass.new.existing_method.should eq(existing_method_return_value)
+ end
- klass.method_defined?(:__existing_method_without_any_instance__).should be_false
- klass.new.existing_method.should eq(2)
- end
+ it "restores the class to its original state after each example when one instance is created" do
+ klass.new.existing_method
- it "restores the class to its original state after each example when one instance is created" do
- klass.new.existing_method
+ space.reset_all
- space.reset_all
+ klass.method_defined?(:__existing_method_without_any_instance__).should be_false
+ klass.new.existing_method.should eq(existing_method_return_value)
+ end
- klass.method_defined?(:__existing_method_without_any_instance__).should be_false
- klass.new.existing_method.should eq(2)
- end
+ it "restores the class to its original state after each example when more than one instance is created" do
+ klass.new.existing_method
+ klass.new.existing_method
- it "restores the class to its original state after each example when more than one instance is created" do
- klass.new.existing_method
- klass.new.existing_method
+ space.reset_all
- space.reset_all
+ klass.method_defined?(:__existing_method_without_any_instance__).should be_false
+ klass.new.existing_method.should eq(existing_method_return_value)
+ end
+ end
+
+ context "with expectations" do
+ context "ensures that the subsequent specs do not see expectations set in previous specs" do
+ context "when the instance created after the expectation is set" do
+ it "first spec" do
+ klass.any_instance.should_receive(:existing_method).and_return(Object.new)
+ klass.new.existing_method
+ end
+
+ it "second spec" do
+ klass.new.existing_method.should eq(existing_method_return_value)
+ end
+ end
+
+ context "when the instance created before the expectation is set" do
+ before :each do
+ @instance = klass.new
+ end
+
+ it "first spec" do
+ klass.any_instance.should_receive(:existing_method).and_return(Object.new)
+ @instance.existing_method
+ end
+
+ it "second spec" do
+ @instance.existing_method.should eq(existing_method_return_value)
+ end
+ end
+ end
+
+ it "ensures that the next spec does not see that expectation" do
+ klass.any_instance.should_receive(:existing_method).and_return(Object.new)
+ klass.new.existing_method
+ space.verify_all
+ space.reset_all
- klass.method_defined?(:__existing_method_without_any_instance__).should be_false
- klass.new.existing_method.should eq(2)
+ klass.new.existing_method.should eq(existing_method_return_value)
+ end
end
end
Please sign in to comment.
Something went wrong with that request. Please try again.