Class: FlexMock::Expectation

Inherits:
Object
  • Object
show all
Defined in:
lib/flexmock/expectation.rb

Overview

An Expectation is returned from each should_receive message sent to mock object. Each expectation records how a message matching the message name (argument to should_receive) and the argument list (given by with) should behave. Mock expectations can be recorded by chaining the declaration methods defined in this class.

For example:

mock.should_receive(:meth).with(args).and_returns(result)

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(mock, sym) ⇒ Expectation

Create an expectation for a method named sym.



34
35
36
37
38
39
40
41
42
43
44
# File 'lib/flexmock/expectation.rb', line 34

def initialize(mock, sym)
  @mock = mock
  @sym = sym
  @expected_args = nil
  @count_validators = []
  @count_validator_class = ExactCountValidator
  @actual_count = 0
  @return_value = nil
  @return_block = lambda { @return_value }
  @order_number = nil
end

Instance Attribute Details

#expected_argsObject (readonly)

Returns the value of attribute expected_args.



30
31
32
# File 'lib/flexmock/expectation.rb', line 30

def expected_args
  @expected_args
end

#mockObject

Returns the value of attribute mock.



31
32
33
# File 'lib/flexmock/expectation.rb', line 31

def mock
  @mock
end

#order_numberObject (readonly)

Returns the value of attribute order_number.



30
31
32
# File 'lib/flexmock/expectation.rb', line 30

def order_number
  @order_number
end

Instance Method Details

#and_return(*args, &block) ⇒ Object Also known as: returns

:call-seq:

and_return(value)
and_return(value, value, ...)
and_return { |*args| code }

Declare that the method returns a particular value (when the argument list is matched).

  • If a single value is given, it will be returned for all matching calls.

  • If multiple values are given, each value will be returned in turn for each successive call. If the number of matching calls is greater than the number of values, the last value will be returned for the extra matching calls.

  • If a block is given, it is evaluated on each call and its value is returned.

For example:

mock.should_receive(:f).returns(12)   # returns 12

mock.should_receive(:f).with(String). # returns an
  returns { |str| str.upcase }        # upcased string

and_return is an alias for returns.



144
145
146
147
148
149
150
151
152
# File 'lib/flexmock/expectation.rb', line 144

def and_return(*args, &block)
  @return_block = 
    if block_given? 
       block
    else
      lambda { args.size == 1 ? args.first : args.shift }
    end
  self
end

#at_leastObject

Modifies the next call count declarator (times, never, once or twice) so that the declarator means the method is called at least that many times.

E.g. method f must be called at least twice:

mock.should_receive(:f).at_least.twice


198
199
200
201
# File 'lib/flexmock/expectation.rb', line 198

def at_least
  @count_validator_class = AtLeastCountValidator
  self
end

#at_mostObject

Modifies the next call count declarator (times, never, once or twice) so that the declarator means the method is called at most that many times.

E.g. method f must be called no more than twice

mock.should_receive(:f).at_most.twice


211
212
213
214
# File 'lib/flexmock/expectation.rb', line 211

def at_most
  @count_validator_class = AtMostCountValidator
  self
end

#eligible?Boolean

Is this expectation eligible to be called again? It is eligible only if all of its count validators agree that it is eligible.

Returns:

  • (Boolean)


60
61
62
# File 'lib/flexmock/expectation.rb', line 60

def eligible?
  @count_validators.all? { |v| v.eligible?(@actual_count) }
end

#match_arg(expected, actual) ⇒ Object

Does the expected argument match the corresponding actual value.



94
95
96
97
98
# File 'lib/flexmock/expectation.rb', line 94

def match_arg(expected, actual)
  expected === actual ||
  expected == actual ||
  ( Regexp === expected && expected === actual.to_s )
end

#match_args(args) ⇒ Object

Does the argument list match this expectation’s argument specification.



85
86
87
88
89
90
91
# File 'lib/flexmock/expectation.rb', line 85

def match_args(args)
  # TODO: Rethink this:
  # return false if @expected_args.nil?
  return true if @expected_args.nil?
  return false if args.size != @expected_args.size
  (0...args.size).all? { |i| match_arg(@expected_args[i], args[i]) }
end

#mock_verifyObject

Validate the correct number of calls have been made. Called by the teardown process.



77
78
79
80
81
# File 'lib/flexmock/expectation.rb', line 77

def mock_verify
  @count_validators.each do |v|
    v.validate(@actual_count)
  end
end

#neverObject

Declare that the method is never expected to be called with the given argument list. This may be modified by the at_least and at_most declarators.



172
173
174
# File 'lib/flexmock/expectation.rb', line 172

def never
  times(0)
end

#onceObject

Declare that the method is expected to be called exactly once with the given argument list. This may be modified by the at_least and at_most declarators.



179
180
181
# File 'lib/flexmock/expectation.rb', line 179

def once
  times(1)
end

#ordered(group_name = nil) ⇒ Object

Declare that the given method must be called in order. All ordered method calls must be received in the order specified by the ordering of the should_receive messages. Receiving a methods out of the specified order will cause a test failure.

If the user needs more fine control over ordering (e.g. specifying that a group of messages may be received in any order as long as they all come after another group of messages), a group name may be specified in the ordered calls. All messages within the same group may be received in any order.

For example, in the following, messages flip and flop may be received in any order (because they are in the same group), but must occur strictly after start but before end. The message any_time may be received at any time because it is not ordered.

m = FlexMock.new
m.should_receive(:any_time)
m.should_receive(:start).ordered
m.should_receive(:flip).ordered(:flip_flop_group)
m.should_receive(:flop).ordered(:flip_flop_group)
m.should_receive(:end).ordered


240
241
242
243
244
245
246
247
248
249
250
# File 'lib/flexmock/expectation.rb', line 240

def ordered(group_name=nil)
  if group_name.nil?
    @order_number = @mock.mock_allocate_order
  elsif (num = @mock.mock_groups[group_name])
    @order_number = num
  else
    @order_number = @mock.mock_allocate_order
    @mock.mock_groups[group_name] = @order_number
  end
  self
end

#times(limit) ⇒ Object

Declare that the method is called limit times with the declared argument list. This may be modified by the at_least and at_most declarators.



163
164
165
166
167
# File 'lib/flexmock/expectation.rb', line 163

def times(limit)
  @count_validators << @count_validator_class.new(self, limit) unless limit.nil?
  @count_validator_class = ExactCountValidator
  self
end

#to_sObject



46
47
48
# File 'lib/flexmock/expectation.rb', line 46

def to_s
  FlexMock.format_args(@sym, @expected_args)
end

#twiceObject

Declare that the method is expected to be called exactly twice with the given argument list. This may be modified by the at_least and at_most declarators.



186
187
188
# File 'lib/flexmock/expectation.rb', line 186

def twice
  times(2)
end

#verify_call(*args) ⇒ Object

Verify the current call with the given arguments matches the expectations recorded in this object.



52
53
54
55
56
# File 'lib/flexmock/expectation.rb', line 52

def verify_call(*args)
  validate_order
  @actual_count += 1
  @return_block.call(*args)
end

#with(*args) ⇒ Object

Declare that the method should expect the given argument list.



101
102
103
104
# File 'lib/flexmock/expectation.rb', line 101

def with(*args)
  @expected_args = args
  self
end

#with_any_argsObject

Declare that the method can be called with any number of arguments of any type.



113
114
115
116
# File 'lib/flexmock/expectation.rb', line 113

def with_any_args
  @expected_args = nil
  self
end

#with_no_argsObject

Declare that the method should be called with no arguments.



107
108
109
# File 'lib/flexmock/expectation.rb', line 107

def with_no_args
  with
end

#zero_or_more_timesObject

Declare that the method may be called any number of times.



156
157
158
# File 'lib/flexmock/expectation.rb', line 156

def zero_or_more_times
  at_least.never
end