Class: RSpec::Mocks::MessageExpectation

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

Direct Known Subclasses

VerifyingMessageExpectation

Instance Attribute Summary (collapse)

Instance Method Summary (collapse)

Constructor Details

- (MessageExpectation) initialize(error_generator, expectation_ordering, expected_from, method_double, expected_received_count = 1, opts = {}, &implementation_block)

Returns a new instance of MessageExpectation



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/rspec/mocks/message_expectation.rb', line 49

def initialize(error_generator, expectation_ordering, expected_from, method_double,
               expected_received_count=1, opts={}, &implementation_block)
  @error_generator = error_generator
  @error_generator.opts = opts
  @expected_from = expected_from
  @method_double = method_double
  @orig_object = @method_double.object
  @message = @method_double.method_name
  @actual_received_count = 0
  @expected_received_count = expected_received_count
  @argument_list_matcher = ArgumentListMatcher::MATCH_ALL
  @order_group = expectation_ordering
  @order_group.register(self)
  @ordered = false
  @at_least = @at_most = @exactly = nil
  @args_to_yield = []
  @failed_fast = nil
  @eval_context = nil
  @yield_receiver_to_implementation_block = false

  @implementation = Implementation.new
  self.inner_implementation_action = implementation_block
end

Instance Attribute Details

- (Object) argument_list_matcher=(value) (writeonly)

Sets the attribute argument_list_matcher

Parameters:

  • value

    the value to set the attribute argument_list_matcher to.



45
46
47
# File 'lib/rspec/mocks/message_expectation.rb', line 45

def argument_list_matcher=(value)
  @argument_list_matcher = value
end

- (Object) implementation



42
43
44
# File 'lib/rspec/mocks/message_expectation.rb', line 42

def implementation
  @implementation
end

- (Object) message (readonly)

Returns the value of attribute message



43
44
45
# File 'lib/rspec/mocks/message_expectation.rb', line 43

def message
  @message
end

- (Object) orig_object (readonly)

Returns the value of attribute orig_object



44
45
46
# File 'lib/rspec/mocks/message_expectation.rb', line 44

def orig_object
  @orig_object
end

Instance Method Details

- (Boolean) actual_received_count_matters?

Returns:

  • (Boolean)


456
457
458
# File 'lib/rspec/mocks/message_expectation.rb', line 456

def actual_received_count_matters?
  @at_least || @at_most || @exactly
end

- (Object) advise(*args)



282
283
284
# File 'lib/rspec/mocks/message_expectation.rb', line 282

def advise(*args)
  similar_messages << args
end

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


138
139
140
141
142
143
144
145
146
# File 'lib/rspec/mocks/message_expectation.rb', line 138

def and_call_original
  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 = AndCallOriginalImplementation.new(@method_double.original_method)
    @yield_receiver_to_implementation_block = false
  end
end

- (Object) and_raise - (Object) and_raise(ExceptionClass) - (Object) and_raise(ExceptionClass, message) - (Object) 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))


169
170
171
172
173
174
175
176
# File 'lib/rspec/mocks/message_expectation.rb', line 169

def and_raise(exception = RuntimeError, message = nil)
  if exception.respond_to?(:exception)
    exception = message ? exception.exception(message) : exception.exception
  end

  self.terminal_implementation_action = Proc.new { raise exception }
  nil
end

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


102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/rspec/mocks/message_expectation.rb', line 102

def and_return(first_value, *values)
  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 and @at_least)
  self.terminal_implementation_action = AndReturnImplementation.new(values)

  nil
end

- (Object) and_throw(symbol) - (Object) 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)


188
189
190
191
# File 'lib/rspec/mocks/message_expectation.rb', line 188

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

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


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

def and_yield(*args, &block)
  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

- (Object) and_yield_receiver_to_implementation



118
119
120
121
# File 'lib/rspec/mocks/message_expectation.rb', line 118

def and_yield_receiver_to_implementation
  @yield_receiver_to_implementation_block = true
  self
end

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


363
364
365
366
367
368
369
370
371
372
373
# File 'lib/rspec/mocks/message_expectation.rb', line 363

def at_least(n, &block)
  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

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


381
382
383
384
385
# File 'lib/rspec/mocks/message_expectation.rb', line 381

def at_most(n, &block)
  self.inner_implementation_action = block
  set_expected_received_count :at_most, n
  self
end

- (Boolean) called_max_times?

Returns:

  • (Boolean)


227
228
229
230
231
232
# File 'lib/rspec/mocks/message_expectation.rb', line 227

def called_max_times?
  @expected_received_count != :any &&
    !@at_least &&
    @expected_received_count > 0 &&
    @actual_received_count >= @expected_received_count
end

- (Object) description



302
303
304
# File 'lib/rspec/mocks/message_expectation.rb', line 302

def description
  @error_generator.describe_expectation(@message, @expected_received_count, @actual_received_count, *expected_args)
end

- (Object) ensure_expected_ordering_received!



251
252
253
254
# File 'lib/rspec/mocks/message_expectation.rb', line 251

def ensure_expected_ordering_received!
  @order_group.verify_invocation_order(self) if @ordered
  true
end

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


351
352
353
354
355
# File 'lib/rspec/mocks/message_expectation.rb', line 351

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

- (Object) expectation_count_type



295
296
297
298
299
# File 'lib/rspec/mocks/message_expectation.rb', line 295

def expectation_count_type
  return :at_least if @at_least
  return :at_most if @at_most
  return nil
end

- (Object) expected_args



74
75
76
# File 'lib/rspec/mocks/message_expectation.rb', line 74

def expected_args
  @argument_list_matcher.expected_args
end

- (Boolean) expected_messages_received?

Returns:

  • (Boolean)


247
248
249
# File 'lib/rspec/mocks/message_expectation.rb', line 247

def expected_messages_received?
  ignoring_args? || matches_exact_count? || matches_at_least_count? || matches_at_most_count?
end

- (Object) generate_error



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

def generate_error
  if similar_messages.empty?
    @error_generator.raise_expectation_error(@message, @expected_received_count, @argument_list_matcher, @actual_received_count, expectation_count_type, *expected_args)
  else
    @error_generator.raise_similar_message_args_error(self, *@similar_messages)
  end
end

- (Boolean) ignoring_args?

Returns:

  • (Boolean)


257
258
259
# File 'lib/rspec/mocks/message_expectation.rb', line 257

def ignoring_args?
  @expected_received_count == :any
end

- (Object) increase_actual_received_count!



461
462
463
# File 'lib/rspec/mocks/message_expectation.rb', line 461

def increase_actual_received_count!
  @actual_received_count += 1
end

- (Object) invoke(parent_stub, *args, &block)



212
213
214
# File 'lib/rspec/mocks/message_expectation.rb', line 212

def invoke(parent_stub, *args, &block)
  invoke_incrementing_actual_calls_by(1, parent_stub, *args, &block)
end

- (Object) invoke_without_incrementing_received_count(parent_stub, *args, &block)



217
218
219
# File 'lib/rspec/mocks/message_expectation.rb', line 217

def invoke_without_incrementing_received_count(parent_stub, *args, &block)
  invoke_incrementing_actual_calls_by(0, parent_stub, *args, &block)
end

- (Boolean) matches?(message, *args)

Returns:

  • (Boolean)


207
208
209
# File 'lib/rspec/mocks/message_expectation.rb', line 207

def matches?(message, *args)
  @message == message && @argument_list_matcher.args_match?(*args)
end

- (Boolean) matches_at_least_count?

Returns:

  • (Boolean)


262
263
264
# File 'lib/rspec/mocks/message_expectation.rb', line 262

def matches_at_least_count?
  @at_least && @actual_received_count >= @expected_received_count
end

- (Boolean) matches_at_most_count?

Returns:

  • (Boolean)


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

def matches_at_most_count?
  @at_most && @actual_received_count <= @expected_received_count
end

- (Boolean) matches_exact_count?

Returns:

  • (Boolean)


272
273
274
# File 'lib/rspec/mocks/message_expectation.rb', line 272

def matches_exact_count?
  @expected_received_count == @actual_received_count
end

- (Object) matches_name_but_not_args(message, *args)



235
236
237
# File 'lib/rspec/mocks/message_expectation.rb', line 235

def matches_name_but_not_args(message, *args)
  @message == message and not @argument_list_matcher.args_match?(*args)
end

- (Boolean) negative?

Returns:

  • (Boolean)


222
223
224
# File 'lib/rspec/mocks/message_expectation.rb', line 222

def negative?
  @expected_received_count == 0 && !@at_least
end

- (Boolean) negative_expectation_for?(message)

Returns:

  • (Boolean)


451
452
453
# File 'lib/rspec/mocks/message_expectation.rb', line 451

def negative_expectation_for?(message)
  @message == message && negative?
end

- (Object) never

Expect a message not to be received at all.

Examples:


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


404
405
406
407
408
# File 'lib/rspec/mocks/message_expectation.rb', line 404

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

- (Object) once(&block)

Expect a message to be received exactly one time.

Examples:


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


415
416
417
418
419
# File 'lib/rspec/mocks/message_expectation.rb', line 415

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

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


439
440
441
442
443
# File 'lib/rspec/mocks/message_expectation.rb', line 439

def ordered(&block)
  self.inner_implementation_action = block
  @ordered = true
  self
end

- (Boolean) ordered?

Returns:

  • (Boolean)


446
447
448
# File 'lib/rspec/mocks/message_expectation.rb', line 446

def ordered?
  @ordered
end

- (Object) raise_out_of_order_error



306
307
308
# File 'lib/rspec/mocks/message_expectation.rb', line 306

def raise_out_of_order_error
  @error_generator.raise_out_of_order_error @message
end

- (Object) similar_messages



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

def similar_messages
  @similar_messages ||= []
end

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


394
395
396
397
# File 'lib/rspec/mocks/message_expectation.rb', line 394

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

- (Object) twice(&block)

Expect a message to be received exactly two times.

Examples:


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


426
427
428
429
430
# File 'lib/rspec/mocks/message_expectation.rb', line 426

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

- (Object) verify_messages_received



240
241
242
243
244
# File 'lib/rspec/mocks/message_expectation.rb', line 240

def verify_messages_received
  InsertOntoBacktrace.line(@expected_from) do
    generate_error unless expected_messages_received? || failed_fast?
  end
end

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


334
335
336
337
338
339
340
341
342
343
# File 'lib/rspec/mocks/message_expectation.rb', line 334

def with(*args, &block)
  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

- (Boolean) yield_receiver_to_implementation_block?

Returns:

  • (Boolean)


123
124
125
# File 'lib/rspec/mocks/message_expectation.rb', line 123

def yield_receiver_to_implementation_block?
  @yield_receiver_to_implementation_block
end