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

#and_call_originalnil

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)


98
99
100
101
102
# File 'lib/rspec/mocks/message_expectation.rb', line 98

def and_call_original
  and_wrap_original do |original, *args, &block|
    original.call(*args, &block)
  end
end

#and_raisenil #and_raise(ExceptionClass) ⇒ nil #and_raise(ExceptionClass, message) ⇒ nil #and_raise(exception_instance) ⇒ nil

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


148
149
150
151
152
# File 'lib/rspec/mocks/message_expectation.rb', line 148

def and_raise(*args)
  raise_already_invoked_error_if_necessary(__method__)
  self.terminal_implementation_action = Proc.new { raise(*args) }
  nil
end

#and_return(value) ⇒ nil #and_return(first_value, second_value) ⇒ nil

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


70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/rspec/mocks/message_expectation.rb', line 70

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

#and_throw(symbol) ⇒ nil #and_throw(symbol, object) ⇒ nil

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)


164
165
166
167
168
# File 'lib/rspec/mocks/message_expectation.rb', line 164

def and_throw(*args)
  raise_already_invoked_error_if_necessary(__method__)
  self.terminal_implementation_action = Proc.new { throw(*args) }
  nil
end

#and_wrap_original(&block) ⇒ nil

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


116
117
118
119
120
121
122
123
124
125
126
# File 'lib/rspec/mocks/message_expectation.rb', line 116

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

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

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)


176
177
178
179
180
181
182
183
184
185
186
187
# File 'lib/rspec/mocks/message_expectation.rb', line 176

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

#at_least(n, &block) ⇒ MessageExpecation

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


211
212
213
214
215
216
217
218
219
220
221
222
# File 'lib/rspec/mocks/message_expectation.rb', line 211

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

#at_most(n, &block) ⇒ MessageExpecation

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


230
231
232
233
234
235
# File 'lib/rspec/mocks/message_expectation.rb', line 230

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

#exactly(n, &block) ⇒ MessageExpecation

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

Examples:

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


198
199
200
201
202
203
# File 'lib/rspec/mocks/message_expectation.rb', line 198

def exactly(n, &block)
  raise_already_invoked_error_if_necessary(__method__)
  self.inner_implementation_action = block
  set_expected_received_count :exactly, n
  self
end

#neverMessageExpecation

Expect a message not to be received at all.

Examples:

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


254
255
256
257
258
# File 'lib/rspec/mocks/message_expectation.rb', line 254

def never
  ErrorGenerator.raise_double_negation_error("expect(obj)") if negative?
  @expected_received_count = 0
  self
end

#once(&block) ⇒ MessageExpecation

Expect a message to be received exactly one time.

Examples:

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


265
266
267
268
269
# File 'lib/rspec/mocks/message_expectation.rb', line 265

def once(&block)
  self.inner_implementation_action = block
  set_expected_received_count :exactly, 1
  self
end

#ordered(&block) ⇒ MessageExpecation

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


339
340
341
342
343
344
345
346
# File 'lib/rspec/mocks/message_expectation.rb', line 339

def ordered(&block)
  self.inner_implementation_action = block
  additional_expected_calls.times do
    @order_group.register(self)
  end
  @ordered = true
  self
end

#thrice(&block) ⇒ MessageExpecation

Expect a message to be received exactly three times.

Examples:

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


287
288
289
290
291
# File 'lib/rspec/mocks/message_expectation.rb', line 287

def thrice(&block)
  self.inner_implementation_action = block
  set_expected_received_count :exactly, 3
  self
end

#times(&block) ⇒ MessageExpecation

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


244
245
246
247
# File 'lib/rspec/mocks/message_expectation.rb', line 244

def times(&block)
  self.inner_implementation_action = block
  self
end

#twice(&block) ⇒ MessageExpecation

Expect a message to be received exactly two times.

Examples:

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


276
277
278
279
280
# File 'lib/rspec/mocks/message_expectation.rb', line 276

def twice(&block)
  self.inner_implementation_action = block
  set_expected_received_count :exactly, 2
  self
end

#with(*args, &block) ⇒ MessageExpecation

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


320
321
322
323
324
325
326
327
328
329
330
# File 'lib/rspec/mocks/message_expectation.rb', line 320

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