Message Expectations
A message expectation (a.k.a. mock method) is an expectation that an object
should receive a specific message during the execution of an example.
Expecting Messages
my_mock.should_receive(<message>)
The message argument is a symbol that is the name of a message
that you want the mock to expect.
You can also specify that a message should not be received:
my_mock.should_not_receive(:msg)
This fails if :msg is ever received.
Expecting Arguments
my_mock.should_receive(:msg).with(<args>) my_mock.should_receive(:msg).once.with(<args>)
for example:
my_mock.should_receive(:msg).with(1, 2, 3) my_mock.should_receive(:msg).once.with(1, 2, 3)
The args argument is a series of arguments (e.g. 1, 2, 3) that are
expected to be passed as arguments to the associated message.
my_mock.should_receive(:msg).with(no_args())
The message (msg) is expected to be passed no arguments.
my_mock.should_receive(:msg).with(any_args())
Any arguments (and any number of arguments) are to be accepted. This includes
cases where no arguments are provided. This is the default when no with()
clause is specified. Even so, sometimes you want to be explicit about it.
Argument Constraints
Constraints can be placed on individual arguments which are looser than value
equivalence (as above).
anything()
accepts any value for this argument, e.g.:
my_mock.should_receive(:msg).with(1, anything(), "A")
an_instance_of()
accepts any numeric value for this argument, e.g.:
my_mock.should_receive(:msg).with(a, an_instance_of(Fixnum), "b")
hash_including()
accepts a hash (with or without curly braces) representing part of or the entire expected hash, e.g.:
my_mock.should_receive(:msg).with(a, "b", hash_including(:c => 'd')) my_mock.should_receive(:msg).with(a, "b", hash_including({:c => 'd'}))
These would pass for:
my_mock.msg(a, 'b', :c = 'd') my_mock.msg(a, 'b', :c = 'd', :e => 'f')
but fail without the precise key/value pairs:
my_mock.msg(a, 'b', :c = 'e') my_mock.msg(a, 'b', :f = 'd')
boolean()
accepts a boolean value for this argument, e.g.:
my_mock.should_receive(:msg).with(a, boolean(), "b")
duck_type(message(s))
accepts any object that responds to the prescribed message(s), e.g.:
#accepts a Fixnum for the second arg my_mock.should_receive(:msg).with(a, duck_type(:abs, :div), "b")
/regular expressions/
matches a String against a regular expression. If a regular expression is submitted, compares the two expressions for equality
my_mock.should_receive(:msg).with(/bcd/) my_mock.msg "abcde" #passes my_mock.msg /bcd/ #passes my_mock.msg "def" #fails my_mock.msg /bcde/ #fails
Receive Counts
The implicit expectation is that the message passed to should_receive will
be called once. You can make the expected counts explicit using the following:
Precise Counts
my_mock.should_receive(:msg).once
An exception is raised if the message is never received, or it is received more than once.
my_mock.should_receive(:msg).twice
An exception is raised if the message is received anything but two times.
my_mock.should_receive(:msg).exactly(n).times
An exception is raised if the message is received anything but n times.
Relative Counts – at_least
my_mock.should_receive(:msg).at_least(:once)
An exception is raised if the message is never received.
my_mock.should_receive(:msg).at_least(:twice)
An exception is raised if the message is never received or is received only once.
my_mock.should_receive(:msg).at_least(n).times
An exception is raised if the message is received fewer than n times.
Relative Counts – at_most
my_mock.should_receive(:msg).at_most(:once)
An exception is raised if the message is received more than once (does not raise if message is never receieved).
my_mock.should_receive(:msg).at_most(:twice)
An exception is raised if the message is received more than twice (does not raise if message is never receieved).
my_mock.should_receive(:msg).at_most(n).times
An exception is raised if the message is received more than n times (does not raise if message is never receieved).
Explicitly Imprecise Counts
my_mock.should_receive(:msg).any_number_of_times
The message can be received 0 or more times.
Return Values
Single return value
my_mock.should_receive(:msg).once.and_return(<value>)
Each time the expected message is received, value will be returned as the result.
Consecutive return values
and_return(<value-1>, <value-2>, ..., <value-n>)
When the expected message is received, value-i will be returned as
the result for the ith reception of the message. After the message has been
received i times, value-n is returned for all
subsequent receives.
Computed return value
my_mock.should_receive(:msg).once.and_return {...}
When the expected message is received, the result of evaluating the supplied
block will be returned as the result. The block is passed any arguments passed
as arguments of the message. This capability can be used to compute return
values based on the arguments. For example:
my_mock.should_receive(:msg).with(instance_of(Numeric),instance_of(Numeric)).once.and_return {|a, b| a + b}
Raising and Throwing
my_mock.should_receive(:msg).once.and_raise(<exception>)
Tells the mock to raise an exception instead of returning a value.
<exception> may be any Exception class, an instance of
any Exception class, or a String (in which case a RuntimeError will be raised
with that String as its message).
my_mock.should_receive(:msg).once.and_throw(<symbol>)
Tells the mock to throw a symbol instead of returning a value.
Yielding
my_mock.should_receive(:msg).once.and_yield(<value-1>, <value-2>, ..., <value-n>)
When the expected message is received, the mock will yield the values to the passed block.
To mock a method which yields values multiple times, and_yield can be chained.
my_mock.should_receive(:msg).once.and_yield(<value-0-1>, <value-0-2>, ..., <value-0-n>). and_yield(<value-1-1>, <value-1-2>, ..., <value-1-n>). and_yield(<value-2-1>, <value-2-2>, ..., <value-2-n>)
Ordering
There are times when you want to specify the order of messages sent to a mock.
It shouldn’t be the case very often, but it can be handy at times.
Labeling expectations as being ordered is done by the ordered call:
my_mock.should_receive(:flip).once.ordered my_mock.should_receive(:flop).once.ordered
If the send of flop is seen before flip the specification will fail.
Of course, chains of ordered expectations can be set up:
my_mock.should_receive(:one).ordered my_mock.should_receive(:two).ordered my_mock.should_receive(:three).ordered
The expected order is the order in which the expectations are declared.
Order-independent expectations can be set anywhere in the expectation sequence, in any order.
Only the order of expectations tagged with the ordered call is significant.
Likewise, calls to order-independent methods can be made in any order, even interspersed with
calls to order-dependent methods. For example:
my_mock.should_receive(:zero) my_mock.should_receive(:one).ordered my_mock.should_receive(:two).ordered my_mock.should_receive(:one_and_a_half) # This will pass: my_mock.one my_mock.one_and_a_half my_mock.zero my_mock.two
Arbitrary Handling of Received Messages
You can supply a block to a message expectation. When the message is received
by the mock, the block is passed any arguments and evaluated. The result is
the return value of the block. For example:
my_mock.should_receive(:msg) { |a, b| a.should be_true b.should_not include('mice') "Chunky bacon!" }
This allows arbitrary argument validation and result computation. It’s handy and kind of cool to be able to
do this, but it is advised to not use this form in most situations. Mocks should not be functional.
They should be completely declarative. That said, it’s sometimes useful to give them some minimal behaviour.