spec/rspec/mocks/any_instance_spec.rb in rspec-mocks-2.6.0 vs spec/rspec/mocks/any_instance_spec.rb in rspec-mocks-2.7.0.rc1

- old
+ new

@@ -1,15 +1,17 @@ + require 'spec_helper' module RSpec module Mocks describe "#any_instance" do class CustomErrorForAnyInstanceSpec < StandardError;end let(:klass) do Class.new do def existing_method; :existing_method_return_value; end + def existing_method_with_arguments(arg_one, arg_two = nil); :existing_method_with_arguments_return_value; end def another_existing_method; end end end let(:existing_method_return_value){ :existing_method_return_value } @@ -29,11 +31,17 @@ it "raises an error if 'with' follows 'and_yield'" do lambda{ klass.any_instance.stub(:foo).and_yield(1).with("1") }.should raise_error(NoMethodError) end end - + + context "#stub_chain" do + it "raises an error if 'stub_chain' follows 'any_instance'" do + lambda{ klass.any_instance.and_return("1").stub_chain(:foo, :bar) }.should raise_error(NoMethodError) + end + end + context "#should_receive" do it "raises an error if 'should_receive' follows 'with'" do lambda{ klass.any_instance.with("1").should_receive(:foo) }.should raise_error(NoMethodError) end @@ -46,17 +54,48 @@ pending "see Github issue #42" lambda{ klass.any_instance.should_receive(:foo).and_raise(1).with("1") }.should raise_error(NoMethodError) end end end - + context "with #stub" do it "does not suppress an exception when a method that doesn't exist is invoked" do klass.any_instance.stub(:foo) lambda{ klass.new.bar }.should raise_error(NoMethodError) end + + context 'multiple methods' do + it "allows multiple methods to be stubbed in a single invocation" do + klass.any_instance.stub(:foo => 'foo', :bar => 'bar') + instance = klass.new + instance.foo.should eq('foo') + instance.bar.should eq('bar') + end + + it "adheres to the contract of multiple method stubbing withou any instance" do + Object.new.stub(:foo => 'foo', :bar => 'bar').should eq(:foo => 'foo', :bar => 'bar') + klass.any_instance.stub(:foo => 'foo', :bar => 'bar').should eq(:foo => 'foo', :bar => 'bar') + end + + context "allows a chain of methods to be stubbed using #stub_chain" do + it "given symbols representing the methods" do + klass.any_instance.stub_chain(:one, :two, :three).and_return(:four) + klass.new.one.two.three.should eq(:four) + end + it "given a hash as the last argument uses the value as the expected return value" do + klass.any_instance.stub_chain(:one, :two, :three => :four) + klass.new.one.two.three.should eq(:four) + end + + it "given a string of '.' separated method names representing the chain" do + klass.any_instance.stub_chain('one.two.three').and_return(:four) + klass.new.one.two.three.should eq(:four) + end + end + 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) @@ -66,11 +105,48 @@ instance = klass.new klass.any_instance.stub(:foo).and_return(result = Object.new) instance.foo.should eq(result) end end + + context "with argument matching" do + before do + klass.any_instance.stub(:foo).with(:param_one, :param_two).and_return(:result_one) + klass.any_instance.stub(:foo).with(:param_three, :param_four).and_return(:result_two) + end + + it "returns the stubbed value when arguments match" do + instance = klass.new + instance.foo(:param_one, :param_two).should eq(:result_one) + instance.foo(:param_three, :param_four).should eq(:result_two) + end + it "fails the spec with an expectation error when the arguments do not match" do + expect do + klass.new.foo(:param_one, :param_three) + end.to(raise_error(RSpec::Mocks::MockExpectationError)) + end + end + + context "with multiple stubs" do + before do + klass.any_instance.stub(:foo).and_return(1) + klass.any_instance.stub(:bar).and_return(2) + end + + it "stubs a method" do + instance = klass.new + instance.foo.should eq(1) + instance.bar.should eq(2) + end + + it "returns the same value for calls on different instances" do + klass.new.foo.should eq(klass.new.foo) + klass.new.bar.should eq(klass.new.bar) + end + end + context "with #and_return" do it "stubs a method that doesn't exist" do klass.any_instance.stub(:foo).and_return(1) klass.new.foo.should eq(1) end @@ -157,11 +233,39 @@ class RSpec::SampleRspecTestClass;end RSpec::SampleRspecTestClass.foo.should eq(1) end end end + + context "unstub implementation" do + it "replaces the stubbed method with the original method" do + klass.any_instance.stub(:existing_method) + klass.any_instance.unstub(:existing_method) + klass.new.existing_method.should eq(:existing_method_return_value) + end + it "removes all stubs with the supplied method name" do + klass.any_instance.stub(:existing_method).with(1) + klass.any_instance.stub(:existing_method).with(2) + klass.any_instance.unstub(:existing_method) + klass.new.existing_method.should eq(:existing_method_return_value) + end + + it "does not remove any expectations with the same method name" do + klass.any_instance.should_receive(:existing_method_with_arguments).with(3).and_return(:three) + klass.any_instance.stub(:existing_method_with_arguments).with(1) + klass.any_instance.stub(:existing_method_with_arguments).with(2) + klass.any_instance.unstub(:existing_method_with_arguments) + klass.new.existing_method_with_arguments(3).should eq :three + end + + it "raises a MockExpectationError if the method has not been stubbed" do + lambda do + klass.any_instance.unstub(:existing_method) + end.should raise_error(RSpec::Mocks::MockExpectationError, 'The method `existing_method` was not stubbed or was already unstubbed') + end + end context "with #should_receive" do let(:foo_expectation_error_message) { 'Exactly one instance should have received the following message(s) but didn\'t: foo' } let(:existing_method_expectation_error_message) { 'Exactly one instance should have received the following message(s) but didn\'t: existing_method' } context "with an expectation is set on a method which does not exist" do @@ -287,9 +391,50 @@ instance_one.existing_method instance_two.existing_method 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 + end + + context "with argument matching" do + before do + klass.any_instance.should_receive(:foo).with(:param_one, :param_two).and_return(:result_one) + klass.any_instance.should_receive(:foo).with(:param_three, :param_four).and_return(:result_two) + end + + it "returns the expected value when arguments match" do + instance = klass.new + instance.foo(:param_one, :param_two).should eq(:result_one) + instance.foo(:param_three, :param_four).should eq(:result_two) + end + + it "fails when the arguments match but different instances are used" do + instances = Array.new(2) { klass.new } + expect do + instances[0].foo(:param_one, :param_two).should eq(:result_one) + instances[1].foo(:param_three, :param_four).should eq(:result_two) + end.to raise_error(RSpec::Mocks::MockExpectationError) + + # ignore the fact that should_receive expectations were not met + instances.each { |instance| instance.rspec_reset } + end + + it "is not affected by the invocation of existing methods on other instances" do + klass.new.existing_method_with_arguments(:param_one, :param_two).should eq(:existing_method_with_arguments_return_value) + instance = klass.new + instance.foo(:param_one, :param_two).should eq(:result_one) + instance.foo(:param_three, :param_four).should eq(:result_two) + end + + it "fails when arguments do not match" do + instance = klass.new + expect do + instance.foo(:param_one, :param_three) + end.to raise_error(RSpec::Mocks::MockExpectationError) + + # ignore the fact that should_receive expectations were not met + instance.rspec_reset end end context "message count" do context "the 'once' constraint" do