require 'spec_helper' module RSpec module Mocks describe "A method stub" do before(:each) do @class = Class.new do class << self def existing_class_method existing_private_class_method end private def existing_private_class_method :original_value end end def existing_instance_method existing_private_instance_method end private def existing_private_instance_method :original_value end end @instance = @class.new @stub = Object.new end [:stub!, :stub].each do |method| describe "using #{method}" do it "returns declared value when message is received" do @instance.send(method, :msg).and_return(:return_value) @instance.msg.should equal(:return_value) @instance.rspec_verify end end end it "instructs an instance to respond_to the message" do @instance.stub(:msg) @instance.should respond_to(:msg) end it "instructs a class object to respond_to the message" do @class.stub(:msg) @class.should respond_to(:msg) end it "ignores when expected message is received with no args" do @instance.stub(:msg) @instance.msg expect do @instance.rspec_verify end.not_to raise_error end it "ignores when message is received with args" do @instance.stub(:msg) @instance.msg(:an_arg) expect do @instance.rspec_verify end.not_to raise_error end it "ignores when expected message is not received" do @instance.stub(:msg) expect do @instance.rspec_verify end.not_to raise_error end it "handles multiple stubbed methods" do @instance.stub(:msg1 => 1, :msg2 => 2) @instance.msg1.should eq(1) @instance.msg2.should eq(2) end describe "#rspec_reset" do it "removes stubbed methods that didn't exist" do @instance.stub(:non_existent_method) @instance.rspec_reset @instance.should_not respond_to(:non_existent_method) end it "restores existing instance methods" do # See bug reports 8302 adn 7805 @instance.stub(:existing_instance_method) { :stub_value } @instance.rspec_reset @instance.existing_instance_method.should eq(:original_value) end it "restores existing private instance methods" do # See bug reports 8302 adn 7805 @instance.stub(:existing_private_instance_method) { :stub_value } @instance.rspec_reset @instance.send(:existing_private_instance_method).should eq(:original_value) end it "restores existing class methods" do # See bug reports 8302 adn 7805 @class.stub(:existing_class_method) { :stub_value } @class.rspec_reset @class.existing_class_method.should eq(:original_value) end it "restores existing private class methods" do # See bug reports 8302 adn 7805 @class.stub(:existing_private_class_method) { :stub_value } @class.rspec_reset @class.send(:existing_private_class_method).should eq(:original_value) end end it "returns values in order to consecutive calls" do @instance.stub(:msg).and_return("1",2,:three) @instance.msg.should eq("1") @instance.msg.should eq(2) @instance.msg.should eq(:three) end it "keeps returning last value in consecutive calls" do @instance.stub(:msg).and_return("1",2,:three) @instance.msg.should eq("1") @instance.msg.should eq(2) @instance.msg.should eq(:three) @instance.msg.should eq(:three) @instance.msg.should eq(:three) end it "yields a specified object" do @instance.stub(:method_that_yields).and_yield(:yielded_obj) current_value = :value_before @instance.method_that_yields {|val| current_value = val} current_value.should eq :yielded_obj @instance.rspec_verify end it "yields multiple times with multiple calls to and_yield" do @instance.stub(:method_that_yields_multiple_times).and_yield(:yielded_value). and_yield(:another_value) current_value = [] @instance.method_that_yields_multiple_times {|val| current_value << val} current_value.should eq [:yielded_value, :another_value] @instance.rspec_verify end it "yields a specified object and return another specified object" do yielded_obj = double("my mock") yielded_obj.should_receive(:foo).with(:bar) @instance.stub(:method_that_yields_and_returns).and_yield(yielded_obj).and_return(:baz) @instance.method_that_yields_and_returns { |o| o.foo :bar }.should eq :baz end it "throws when told to" do @stub.stub(:something).and_throw(:up) expect { @stub.something }.to throw_symbol(:up) end it "throws with argument when told to" do @stub.stub(:something).and_throw(:up, 'high') expect { @stub.something }.to throw_symbol(:up, 'high') end it "overrides a pre-existing method" do @stub.stub(:existing_instance_method).and_return(:updated_stub_value) @stub.existing_instance_method.should eq :updated_stub_value end it "overrides a pre-existing stub" do @stub.stub(:foo) { 'bar' } @stub.stub(:foo) { 'baz' } @stub.foo.should eq 'baz' end it "allows a stub and an expectation" do @stub.stub(:foo).with("bar") @stub.should_receive(:foo).with("baz") @stub.foo("bar") @stub.foo("baz") end it "calculates return value by executing block passed to #and_return" do @stub.stub(:something).with("a","b","c").and_return { |a,b,c| c+b+a } @stub.something("a","b","c").should eq "cba" @stub.rspec_verify end end describe "A method stub with args" do before(:each) do @stub = Object.new @stub.stub(:foo).with("bar") end it "does not complain if not called" do end it "does not complain if called with arg" do @stub.foo("bar") end it "complains if called with no arg" do lambda do @stub.foo end.should raise_error(/received :foo with unexpected arguments/) end it "complains if called with other arg" do lambda do @stub.foo("other") end.should raise_error(/received :foo with unexpected arguments/) end it "does not complain if also mocked w/ different args" do @stub.should_receive(:foo).with("baz") @stub.foo("bar") @stub.foo("baz") end it "complains if also mocked w/ different args AND called w/ a 3rd set of args" do @stub.should_receive(:foo).with("baz") @stub.foo("bar") @stub.foo("baz") lambda do @stub.foo("other") end.should raise_error end it "supports options" do @stub.stub(:foo, :expected_from => "bar") end end end end