class RSpec::Mocks::MessageExpectation
Represents an individual method stub or message expectation. The methods defined here can be used to configure how it behaves. The methods return `self` so that they can be chained together to form a fluent interface.
Public Instance Methods
Tells the object to delegate to the original unmodified method when it receives the message.
@note This is only available on partial doubles.
@return [nil] No further chaining is supported after this. @example
expect(counter).to receive(:increment).and_call_original original_count = counter.count counter.increment expect(counter.count).to eq(original_count + 1)
# File lib/rspec/mocks/message_expectation.rb, line 97 def and_call_original wrap_original(__method__) do |original, *args, &block| original.call(*args, &block) end end
@overload #and_raise @overload #and_raise(ExceptionClass) @overload #and_raise(ExceptionClass, message) @overload #and_raise(exception_instance)
Tells the object to raise an exception when the message is received.
@return [nil] No further chaining is supported after this. @note
When you pass an exception class, the MessageExpectation will raise an instance of it, creating it with `exception` and passing `message` if specified. If the exception class initializer requires more than one parameters, you must pass in an instance and not the class, otherwise this method will raise an ArgumentError exception.
@example
allow(car).to receive(:go).and_raise allow(car).to receive(:go).and_raise(OutOfGas) allow(car).to receive(:go).and_raise(OutOfGas, "At least 2 oz of gas needed to drive") allow(car).to receive(:go).and_raise(OutOfGas.new(2, :oz))
# File lib/rspec/mocks/message_expectation.rb, line 139 def and_raise(*args) raise_already_invoked_error_if_necessary(__method__) self.terminal_implementation_action = Proc.new { raise(*args) } nil end
@overload #and_return(value) @overload #and_return(first_value, second_value)
Tells the object to return a value when it receives the message. Given more than one value, the first value is returned the first time the message is received, the second value is returned the next time, etc, etc.
If the message is received more times than there are values, the last value is received for every subsequent call.
@return [nil] No further chaining is supported after this. @example
allow(counter).to receive(:count).and_return(1) counter.count # => 1 counter.count # => 1 allow(counter).to receive(:count).and_return(1,2,3) counter.count # => 1 counter.count # => 2 counter.count # => 3 counter.count # => 3 counter.count # => 3 # etc
# File lib/rspec/mocks/message_expectation.rb, line 69 def and_return(first_value, *values) raise_already_invoked_error_if_necessary(__method__) if negative? raise "`and_return` is not supported with negative message expectations" end if block_given? raise ArgumentError, "Implementation blocks aren't supported with `and_return`" end values.unshift(first_value) @expected_received_count = [@expected_received_count, values.size].max unless ignoring_args? || (@expected_received_count == 0 && @at_least) self.terminal_implementation_action = AndReturnImplementation.new(values) nil end
@overload #and_throw(symbol) @overload #and_throw(symbol, object)
Tells the object to throw a symbol (with the object if that form is used) when the message is received.
@return [nil] No further chaining is supported after this. @example
allow(car).to receive(:go).and_throw(:out_of_gas) allow(car).to receive(:go).and_throw(:out_of_gas, :level => 0.1)
# File lib/rspec/mocks/message_expectation.rb, line 155 def and_throw(*args) raise_already_invoked_error_if_necessary(__method__) self.terminal_implementation_action = Proc.new { throw(*args) } nil end
Decorates the stubbed method with the supplied block. The original unmodified method is passed to the block along with any method call arguments so you can delegate to it, whilst still being able to change what args are passed to it and/or change the return value.
@note This is only available on partial doubles.
@return [nil] No further chaining is supported after this. @example
expect(api).to receive(:large_list).and_wrap_original do |original_method, *args, &block| original_method.call(*args, &block).first(10) end
# File lib/rspec/mocks/message_expectation.rb, line 115 def and_wrap_original(&block) wrap_original(__method__, &block) end
Tells the object to yield one or more args to a block when the message is received.
@return [MessageExpectation] self, to support further chaining. @example
stream.stub(:open).and_yield(StringIO.new)
# File lib/rspec/mocks/message_expectation.rb, line 167 def and_yield(*args, &block) raise_already_invoked_error_if_necessary(__method__) yield @eval_context = Object.new if block # Initialize args to yield now that it's being used, see also: comment # in constructor. @args_to_yield ||= [] @args_to_yield << args self.initial_implementation_action = AndYieldImplementation.new(@args_to_yield, @eval_context, @error_generator) self end
Constrain a message expectation to be received at least a specific number of times.
@return [MessageExpectation] self, to support further chaining. @example
expect(dealer).to receive(:deal_card).at_least(9).times
# File lib/rspec/mocks/message_expectation.rb, line 202 def at_least(n, &block) raise_already_invoked_error_if_necessary(__method__) set_expected_received_count :at_least, n if n == 0 raise "at_least(0) has been removed, use allow(...).to receive(:message) instead" end self.inner_implementation_action = block self end
Constrain a message expectation to be received at most a specific number of times.
@return [MessageExpectation] self, to support further chaining. @example
expect(dealer).to receive(:deal_card).at_most(10).times
# File lib/rspec/mocks/message_expectation.rb, line 221 def at_most(n, &block) raise_already_invoked_error_if_necessary(__method__) self.inner_implementation_action = block set_expected_received_count :at_most, n self end
Constrain a message expectation to be received a specific number of times.
@return [MessageExpectation] self, to support further chaining. @example
expect(dealer).to receive(:deal_card).exactly(10).times
# File lib/rspec/mocks/message_expectation.rb, line 189 def exactly(n, &block) raise_already_invoked_error_if_necessary(__method__) self.inner_implementation_action = block set_expected_received_count :exactly, n self end
Expect a message not to be received at all.
@return [MessageExpectation] self, to support further chaining. @example
expect(car).to receive(:stop).never
# File lib/rspec/mocks/message_expectation.rb, line 245 def never error_generator.raise_double_negation_error("expect(obj)") if negative? @expected_received_count = 0 self end
Expect a message to be received exactly one time.
@return [MessageExpectation] self, to support further chaining. @example
expect(car).to receive(:go).once
# File lib/rspec/mocks/message_expectation.rb, line 256 def once(&block) self.inner_implementation_action = block set_expected_received_count :exactly, 1 self end
Expect messages to be received in a specific order.
@return [MessageExpectation] self, to support further chaining. @example
expect(api).to receive(:prepare).ordered expect(api).to receive(:run).ordered expect(api).to receive(:finish).ordered
# File lib/rspec/mocks/message_expectation.rb, line 330 def ordered(&block) if type == :stub RSpec.warning( "`allow(...).to receive(..).ordered` is not supported and will" "have no effect, use `and_return(*ordered_values)` instead." ) end self.inner_implementation_action = block additional_expected_calls.times do @order_group.register(self) end @ordered = true self end
Expect a message to be received exactly three times.
@return [MessageExpectation] self, to support further chaining. @example
expect(car).to receive(:go).thrice
# File lib/rspec/mocks/message_expectation.rb, line 278 def thrice(&block) self.inner_implementation_action = block set_expected_received_count :exactly, 3 self end
Syntactic sugar for `exactly`, `at_least` and `at_most`
@return [MessageExpectation] self, to support further chaining. @example
expect(dealer).to receive(:deal_card).exactly(10).times expect(dealer).to receive(:deal_card).at_least(10).times expect(dealer).to receive(:deal_card).at_most(10).times
# File lib/rspec/mocks/message_expectation.rb, line 235 def times(&block) self.inner_implementation_action = block self end
@return [String] a nice representation of the message expectation
# File lib/rspec/mocks/message_expectation.rb, line 347 def to_s args_description = error_generator.method_call_args_description(@argument_list_matcher.expected_args, "", "") { true } args_description = "(#{args_description})" unless args_description.start_with?("(") "#<#{self.class} #{error_generator.intro}.#{message}#{args_description}>" end
Expect a message to be received exactly two times.
@return [MessageExpectation] self, to support further chaining. @example
expect(car).to receive(:go).twice
# File lib/rspec/mocks/message_expectation.rb, line 267 def twice(&block) self.inner_implementation_action = block set_expected_received_count :exactly, 2 self end
Constrains a stub or message expectation to invocations with specific arguments.
With a stub, if the message might be received with other args as well, you should stub a default value first, and then stub or mock the same message using `with` to constrain to specific arguments.
A message expectation will fail if the message is received with different arguments.
@return [MessageExpectation] self, to support further chaining. @example
allow(cart).to receive(:add) { :failure } allow(cart).to receive(:add).with(Book.new(:isbn => 1934356379)) { :success } cart.add(Book.new(:isbn => 1234567890)) # => :failure cart.add(Book.new(:isbn => 1934356379)) # => :success expect(cart).to receive(:add).with(Book.new(:isbn => 1934356379)) { :success } cart.add(Book.new(:isbn => 1234567890)) # => failed expectation cart.add(Book.new(:isbn => 1934356379)) # => passes
# File lib/rspec/mocks/message_expectation.rb, line 311 def with(*args, &block) raise_already_invoked_error_if_necessary(__method__) if args.empty? raise ArgumentError, "`with` must have at least one argument. Use `no_args` matcher to set the expectation of receiving no arguments." end self.inner_implementation_action = block @argument_list_matcher = ArgumentListMatcher.new(*args) self end