lib/rspec/mocks.rb



require 'rspec/mocks/framework'
require 'rspec/mocks/extensions/object'
require 'rspec/mocks/version'

module RSpec
  # == Test Doubles
  #
  # A Test Double is an object that stands in for a real object in a test.
  # RSpec creates test doubles that support method stubs and message
  # expectations.
  #
  #   book = double("book")
  #
  # == Method Stubs
  #
  # A method stub is an implementation that returns a pre-determined value.
  #
  #   book = double("book")
  #   double.stub(:title) { "The RSpec Book" }
  #   double.title => "The RSpec Book"
  #
  # When we declare a stub, we way we "stubbing" a method.
  #
  # == Message Expectations
  #
  # A message expectation is an expectation that the test double will receive a
  # message some time before the example ends. If the message is received, the
  # expectation is satisfied. If not, the example fails.
  #
  #   registrar = double("registrar")
  #   validator.should_receive(:validate).with("02134")
  #   zipcode = Zipcode.new("02134", validator)
  #   zipcode.valid?
  #   
  # When we declare a message expectation, we way we "mocking" a method.
  #
  # == Mock Objects and Test Stubs
  #
  # The names Mock Object and Test Stub suggest specialized Test Doubles.  i.e.
  # Test Stub evokes Test Double that only supports method stubs, and a Mock
  # Object evokes a Test Double that only supports message expectations, or
  # sometimes supports message expectations in addition to method stubs.
  #
  # There is a lot of overlapping nomenclature here, and there are many
  # variations of these patterns (fakes, spies, etc). Keep in mind that most of
  # the time we're talking about method-level concepts that are variations of
  # method stubs and message expectations, and we're applying to them to _one_
  # generic kind of object: a Test Double.
  #
  # == Test-Specific Extension
  #
  # a.k.a. Partial Stub/Mock, a Test-Specific Extension is an extension of a
  # real object in a system that is instrumented with test-double like
  # behaviour in the context of a test. This technique is very common in Ruby
  # because we often see class objects acting as global namespaces for methods.
  # For example, in Rails:
  #
  #   person = double("person")
  #   Person.stub(:find) { person }
  #
  # In this case we're instrumenting Person to return the person object we've
  # defined whenever it receives the +find+ message. We can do this with any
  # object in a system because RSpec adds the +stub+ and +should_receive+
  # methods to every object. When we use either, RSpec replaces the method
  # we're stubbing or mocking with it's own test-double-like method. At the
  # end of the example, RSpec verifies any message expectations, and then
  # restores the original methods.
  # 
  # == Expecting Arguments
  #
  #   double.should_receive(:msg).with(*args)
  #   double.should_not_receive(:msg).with(*args)
  #
  # == Argument Matchers
  #
  # Arguments that are passed to #with are compared with actual arguments received
  # using == by default. In cases in which you want to specify things about the arguments
  # rather than the arguments themselves, you can use any of RSpec's Expression Matchers.
  # They don't all make syntactic sense (they were primarily designed for use with
  # RSpec::Expectations), but you are free to create your own custom RSpec::Matchers.
  #
  # RSpec::Mocks does provide one additional Matcher method named #ducktype.
  #
  # In addition, RSpec::Mocks adds some keyword Symbols that you can use to
  # specify certain kinds of arguments:
  #
  #   double.should_receive(:msg).with(no_args())
  #   double.should_receive(:msg).with(any_args())
  #   double.should_receive(:msg).with(1, kind_of(Numeric), "b") #2nd argument can any kind of Numeric
  #   double.should_receive(:msg).with(1, boolean(), "b") #2nd argument can true or false
  #   double.should_receive(:msg).with(1, /abc/, "b") #2nd argument can be any String matching the submitted Regexp
  #   double.should_receive(:msg).with(1, anything(), "b") #2nd argument can be anything at all
  #   double.should_receive(:msg).with(1, ducktype(:abs, :div), "b")
  #                            #2nd argument can be object that responds to #abs and #div
  #                                                                       
  # == Receive Counts
  #
  #   double.should_receive(:msg).once
  #   double.should_receive(:msg).twice
  #   double.should_receive(:msg).exactly(n).times
  #   double.should_receive(:msg).at_least(:once)
  #   double.should_receive(:msg).at_least(:twice)
  #   double.should_receive(:msg).at_least(n).times
  #   double.should_receive(:msg).at_most(:once)
  #   double.should_receive(:msg).at_most(:twice)
  #   double.should_receive(:msg).at_most(n).times
  #   double.should_receive(:msg).any_number_of_times
  #
  # == Ordering
  #
  #   double.should_receive(:msg).ordered
  #   double.should_receive(:other_msg).ordered
  #     #This will fail if the messages are received out of order
  #
  # == Setting Reponses
  #
  # Whether you are setting a message expectation or a method stub, you can
  # tell the object precisely how to respond. The most generic way is to pass
  # a block to +stub+ or +should_receive+:
  #
  #   double.should_receive(:msg) { value }
  #
  # When the double receives the +msg+ message, it evaluates the block and returns
  # the result.
  #
  #   double.should_receive(:msg).and_return(value)
  #   double.should_receive(:msg).exactly(3).times.and_return(value1, value2, value3)
  #     # returns value1 the first time, value2 the second, etc
  #   double.should_receive(:msg).and_raise(error)
  #     #error can be an instantiated object or a class
  #     #if it is a class, it must be instantiable with no args
  #   double.should_receive(:msg).and_throw(:msg)
  #   double.should_receive(:msg).and_yield(values,to,yield)
  #   double.should_receive(:msg).and_yield(values,to,yield).and_yield(some,other,values,this,time)
  #     # for methods that yield to a block multiple times
  #
  # Any of these responses can be applied to a stub as well
  #
  #   double.stub(:msg).and_return(value)
  #   double.stub(:msg).and_return(value1, value2, value3)
  #   double.stub(:msg).and_raise(error)
  #   double.stub(:msg).and_throw(:msg)
  #   double.stub(:msg).and_yield(values,to,yield)
  #   double.stub(:msg).and_yield(values,to,yield).and_yield(some,other,values,this,time)
  #
  # == Arbitrary Handling
  #
  # Once in a while you'll find that the available expectations don't solve the
  # particular problem you are trying to solve. Imagine that you expect the message
  # to come with an Array argument that has a specific length, but you don't care
  # what is in it. You could do this:
  #
  #   double.should_receive(:msg) do |arg|
  #     arg.should be_an_istance_of(Array)
  #     arg.length.should == 7
  #   end
  #
  # == Combining Expectation Details
  #
  # Combining the message name with specific arguments, receive counts and responses
  # you can get quite a bit of detail in your expectations:
  #
  #   double.should_receive(:<<).with("illegal value").once.and_raise(ArgumentError)
  #
  # == Further Reading
  # 
  # There are many different viewpoints about the meaning of mocks and stubs. If you are interested
  # in learning more, here is some recommended reading:
  # 
  # * Mock Objects: http://www.mockobjects.com/
  # * Endo-Testing: http://www.mockobjects.com/files/endotesting.pdf
  # * Mock Roles, Not Objects: http://www.mockobjects.com/files/mockrolesnotobjects.pdf
  # * Test Double Patterns: http://xunitpatterns.com/Test%20Double%20Patterns.html
  # * Mocks aren't stubs: http://www.martinfowler.com/articles/mocksArentStubs.html
  module Mocks
  end
end