Class: RSpec::Mocks::MessageExpectation

Inherits:
Object
  • Object
show all
Defined in:
lib/rspec/mocks/message_expectation.rb

Overview

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.

Direct Known Subclasses

VerifyingMessageExpectation

Configuring Responses (collapse)

Constraining Receive Counts (collapse)

Other Constraints (collapse)

Instance Method Details

- (nil) and_call_original

Note:

This is only available on partial doubles.

Tells the object to delegate to the original unmodified method when it receives the message.

Examples:

expect(counter).to receive(:increment).and_call_original
original_count = counter.count
counter.increment
expect(counter.count).to eq(original_count + 1)

Returns:

  • (nil)

    No further chaining is supported after this.

95
96
97
98
99
# File 'lib/rspec/mocks/message_expectation.rb', line 95
def and_call_original
  and_wrap_original do |original, *args, &block|
    original.call(*args, &block)
  end
end

- (nil) and_raise - (nil) and_raise(ExceptionClass) - (nil) and_raise(ExceptionClass, message) - (nil) and_raise(exception_instance)

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.

Tells the object to raise an exception when the message is received.

Examples:

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))

Returns:

  • (nil)

    No further chaining is supported after this.

145
146
147
148
149
150
151
152
153
# File 'lib/rspec/mocks/message_expectation.rb', line 145
def and_raise(exception=RuntimeError, message=nil)
  raise_already_invoked_error_if_necessary(__method__)
  if exception.respond_to?(:exception)
    exception = message ? exception.exception(message) : exception.exception
  end
  self.terminal_implementation_action = Proc.new { raise exception }
  nil
end

- (nil) and_return(value) - (nil) 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.

Examples:

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

Returns:

  • (nil)

    No further chaining is supported after this.

67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/rspec/mocks/message_expectation.rb', line 67
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

- (nil) and_throw(symbol) - (nil) and_throw(symbol, object)

Tells the object to throw a symbol (with the object if that form is used) when the message is received.

Examples:

allow(car).to receive(:go).and_throw(:out_of_gas)
allow(car).to receive(:go).and_throw(:out_of_gas, :level => 0.1)

Returns:

  • (nil)

    No further chaining is supported after this.

165
166
167
168
169
# File 'lib/rspec/mocks/message_expectation.rb', line 165
def and_throw(*args)
  raise_already_invoked_error_if_necessary(__method__)
  self.terminal_implementation_action = Proc.new { throw(*args) }
  nil
end

- (nil) and_wrap_original(&block)

Note:

This is only available on partial doubles.

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.

Examples:

expect(api).to receive(:large_list).and_wrap_original do |original_method, *args, &block|
  original_method.call(*args, &block).first(10)
end

Returns:

  • (nil)

    No further chaining is supported after this.

113
114
115
116
117
118
119
120
121
122
123
# File 'lib/rspec/mocks/message_expectation.rb', line 113
def and_wrap_original(&block)
  if RSpec::Mocks::TestDouble === @method_double.object
    @error_generator.raise_only_valid_on_a_partial_double(:and_call_original)
  else
    warn_about_stub_override if implementation.inner_action
    @implementation = AndWrapOriginalImplementation.new(@method_double.original_method, block)
    @yield_receiver_to_implementation_block = false
  end
  nil
end

- (MessageExpecation) and_yield(*args) {|@eval_context = Object.new| ... }

Tells the object to yield one or more args to a block when the message is received.

Examples:

stream.stub(:open).and_yield(StringIO.new)

Yields:

  • (@eval_context = Object.new)

Returns:

  • (MessageExpecation)

    self, to support further chaining.

177
178
179
180
181
182
183
# File 'lib/rspec/mocks/message_expectation.rb', line 177
def and_yield(*args, &block)
  raise_already_invoked_error_if_necessary(__method__)
  yield @eval_context = Object.new if block
  @args_to_yield << args
  self.initial_implementation_action = AndYieldImplementation.new(@args_to_yield, @eval_context, @error_generator)
  self
end

- (MessageExpecation) at_least(n, &block)

Constrain a message expectation to be received at least a specific number of times.

Examples:

expect(dealer).to receive(:deal_card).at_least(9).times

Returns:

  • (MessageExpecation)

    self, to support further chaining.

207
208
209
210
211
212
213
214
215
216
217
218
# File 'lib/rspec/mocks/message_expectation.rb', line 207
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

- (MessageExpecation) at_most(n, &block)

Constrain a message expectation to be received at most a specific number of times.

Examples:

expect(dealer).to receive(:deal_card).at_most(10).times

Returns:

  • (MessageExpecation)

    self, to support further chaining.

226
227
228
229
230
231
# File 'lib/rspec/mocks/message_expectation.rb', line 226
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

- (MessageExpecation) exactly(n, &block)

Constrain a message expectation to be received a specific number of times.

Examples:

expect(dealer).to receive(:deal_card).exactly(10).times

Returns:

  • (MessageExpecation)

    self, to support further chaining.

194
195
196
197
198
199
# File 'lib/rspec/mocks/message_expectation.rb', line 194
def exactly(n, &block)
  raise_already_invoked_error_if_necessary(__method__)
  self.inner_implementation_action = block
  set_expected_received_count :exactly, n
  self
end

- (MessageExpecation) never

Expect a message not to be received at all.

Examples:

expect(car).to receive(:stop).never

Returns:

  • (MessageExpecation)

    self, to support further chaining.

250
251
252
253
254
# File 'lib/rspec/mocks/message_expectation.rb', line 250
def never
  ErrorGenerator.raise_double_negation_error("expect(obj)") if negative?
  @expected_received_count = 0
  self
end

- (MessageExpecation) once(&block)

Expect a message to be received exactly one time.

Examples:

expect(car).to receive(:go).once

Returns:

  • (MessageExpecation)

    self, to support further chaining.

261
262
263
264
265
# File 'lib/rspec/mocks/message_expectation.rb', line 261
def once(&block)
  self.inner_implementation_action = block
  set_expected_received_count :exactly, 1
  self
end

- (MessageExpecation) ordered(&block)

Expect messages to be received in a specific order.

Examples:

expect(api).to receive(:prepare).ordered
expect(api).to receive(:run).ordered
expect(api).to receive(:finish).ordered

Returns:

  • (MessageExpecation)

    self, to support further chaining.

335
336
337
338
339
340
341
342
# File 'lib/rspec/mocks/message_expectation.rb', line 335
def ordered(&block)
  self.inner_implementation_action = block
  additional_expected_calls.times do
    @order_group.register(self)
  end
  @ordered = true
  self
end

- (MessageExpecation) thrice(&block)

Expect a message to be received exactly three times.

Examples:

expect(car).to receive(:go).thrice

Returns:

  • (MessageExpecation)

    self, to support further chaining.

283
284
285
286
287
# File 'lib/rspec/mocks/message_expectation.rb', line 283
def thrice(&block)
  self.inner_implementation_action = block
  set_expected_received_count :exactly, 3
  self
end

- (MessageExpecation) times(&block)

Syntactic sugar for exactly, at_least and at_most

Examples:

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

Returns:

  • (MessageExpecation)

    self, to support further chaining.

240
241
242
243
# File 'lib/rspec/mocks/message_expectation.rb', line 240
def times(&block)
  self.inner_implementation_action = block
  self
end

- (MessageExpecation) twice(&block)

Expect a message to be received exactly two times.

Examples:

expect(car).to receive(:go).twice

Returns:

  • (MessageExpecation)

    self, to support further chaining.

272
273
274
275
276
# File 'lib/rspec/mocks/message_expectation.rb', line 272
def twice(&block)
  self.inner_implementation_action = block
  set_expected_received_count :exactly, 2
  self
end

- (MessageExpecation) with(*args, &block)

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.

Examples:

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

Returns:

  • (MessageExpecation)

    self, to support further chaining.

316
317
318
319
320
321
322
323
324
325
326
# File 'lib/rspec/mocks/message_expectation.rb', line 316
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