Class: Mocha::Expectation

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

Overview

Methods on expectations returned from Mock#expects, Mock#stubs, ObjectMethods#expects and ObjectMethods#stubs.

Instance Method Summary collapse

Instance Method Details

#at_least(minimum_number_of_times) ⇒ Expectation

Modifies expectation so that the expected method must be called at least a minimum_number_of_times.

Examples:

Expected method must be called at least twice.

object = mock()
object.expects(:expected_method).at_least(2)
3.times { object.expected_method }
# => verify succeeds

object = mock()
object.expects(:expected_method).at_least(2)
object.expected_method
# => verify fails

Parameters:

  • minimum_number_of_times (Integer)

    minimum number of expected invocations.

Returns:



132
133
134
135
# File 'lib/mocha/expectation.rb', line 132

def at_least(minimum_number_of_times)
  @cardinality.at_least(minimum_number_of_times)
  self
end

#at_least_onceExpectation

Modifies expectation so that the expected method must be called at least once.

Examples:

Expected method must be called at least once.

object = mock()
object.expects(:expected_method).at_least_once
object.expected_method
# => verify succeeds

object = mock()
object.expects(:expected_method).at_least_once
# => verify fails

Returns:



150
151
152
# File 'lib/mocha/expectation.rb', line 150

def at_least_once
  at_least(1)
end

#at_most(maximum_number_of_times) ⇒ Expectation

Modifies expectation so that the expected method must be called at most a maximum_number_of_times.

Examples:

Expected method must be called at most twice.

object = mock()
object.expects(:expected_method).at_most(2)
2.times { object.expected_method }
# => verify succeeds

object = mock()
object.expects(:expected_method).at_most(2)
3.times { object.expected_method } # => unexpected invocation

Parameters:

  • maximum_number_of_times (Integer)

    maximum number of expected invocations.

Returns:



168
169
170
171
# File 'lib/mocha/expectation.rb', line 168

def at_most(maximum_number_of_times)
  @cardinality.at_most(maximum_number_of_times)
  self
end

#at_most_onceExpectation

Modifies expectation so that the expected method must be called at most once.

Examples:

Expected method must be called at most once.

object = mock()
object.expects(:expected_method).at_most_once
object.expected_method
# => verify succeeds

object = mock()
object.expects(:expected_method).at_most_once
2.times { object.expected_method } # => unexpected invocation

Returns:



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

def at_most_once
  at_most(1)
end

#in_sequence(sequence, *sequences) ⇒ Expectation

Constrains the expectation so that it must be invoked at the current point in the sequence.

To expect a sequence of invocations, write the expectations in order and add the in_sequence(sequence) clause to each one.

Expectations in a sequence can have any invocation count.

If an expectation in a sequence is stubbed, rather than expected, it can be skipped in the sequence.

An expected method can appear in multiple sequences.

Examples:

Ensure methods are invoked in a specified order.

breakfast = sequence('breakfast')

egg = mock('egg')
egg.expects(:crack).in_sequence(breakfast)
egg.expects(:fry).in_sequence(breakfast)
egg.expects(:eat).in_sequence(breakfast)

Parameters:

  • sequence (Sequence)

    sequence in which expected method should appear.

  • sequences (*Array<Sequence>)

    more sequences in which expected method should appear.

Returns:

See Also:



539
540
541
542
# File 'lib/mocha/expectation.rb', line 539

def in_sequence(sequence, *sequences)
  sequences.unshift(sequence).each { |seq| add_in_sequence_ordering_constraint(seq) }
  self
end

#multiple_yields(*parameter_groups) ⇒ Expectation

Modifies expectation so that when the expected method is called, it yields multiple times per invocation with the specified parameter_groups.

If no block is provided, the method will still attempt to yield resulting in a LocalJumpError. Note that this is what would happen if a “real” (non-mock) method implementation tried to yield to a non-existent block.

Examples:

When foreach is called, the stub will invoke the block twice, the first time it passes [‘row1_col1’, ‘row1_col2’] as the parameters, and the second time it passes [‘row2_col1’, ”] as the parameters.

csv = mock()
csv.expects(:foreach).with("path/to/file.csv").multiple_yields(['row1_col1', 'row1_col2'], ['row2_col1', ''])
rows = []
csv.foreach { |row| rows << row }
rows # => [['row1_col1', 'row1_col2'], ['row2_col1', '']]

Yield different groups of parameters on different invocations of the expected method. Simulating a situation where the CSV file at ‘path/to/file.csv’ has been modified between the two calls to foreach.

csv = mock()
csv.stubs(:foreach).with("path/to/file.csv").multiple_yields(['old_row1_col1', 'old_row1_col2'], ['old_row2_col1', '']).then.multiple_yields(['new_row1_col1', ''], ['new_row2_col1', 'new_row2_col2'])
rows_from_first_invocation = []
rows_from_second_invocation = []
csv.foreach { |row| rows_from_first_invocation << row } # first invocation
csv.foreach { |row| rows_from_second_invocation << row } # second invocation
rows_from_first_invocation # => [['old_row1_col1', 'old_row1_col2'], ['old_row2_col1', '']]
rows_from_second_invocation # => [['new_row1_col1', ''], ['new_row2_col1', 'new_row2_col2']]

Parameters:

  • parameter_groups (*Array<Array>)

    each element of parameter_groups should iself be an Array representing the parameters to be passed to the block for a single yield. Any element of parameter_groups that is not an Array is wrapped in an Array.

Returns:

See Also:



326
327
328
329
# File 'lib/mocha/expectation.rb', line 326

def multiple_yields(*parameter_groups)
  @yield_parameters.add(*parameter_groups)
  self
end

#neverExpectation

Modifies expectation so that the expected method must never be called.

Examples:

Expected method must never be called.

object = mock()
object.expects(:expected_method).never
object.expected_method # => unexpected invocation

object = mock()
object.expects(:expected_method).never
# => verify succeeds

Returns:



112
113
114
115
# File 'lib/mocha/expectation.rb', line 112

def never
  @cardinality.exactly(0)
  self
end

#onceExpectation

Modifies expectation so that the expected method must be called exactly once.

Note that this is the default behaviour for an expectation, but you may wish to use it for clarity/emphasis.

Examples:

Expected method must be invoked exactly once.

object = mock()
object.expects(:expected_method).once
object.expected_method
# => verify succeeds

object = mock()
object.expects(:expected_method).once
object.expected_method
object.expected_method # => unexpected invocation

object = mock()
object.expects(:expected_method).once
# => verify fails

Returns:



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

def once
  @cardinality.exactly(1)
  self
end

#raisesExpectation #raises(exception) ⇒ Expectation #raises(exception, message) ⇒ Expectation

Modifies expectation so that when the expected method is called, it raises the specified exception with the specified message i.e. calls Kernel#raise(exception, message).

Examples:

Raise specified exception if expected method is invoked.

object = stub()
object.stubs(:expected_method).raises(Exception, 'message')
object.expected_method # => raises exception of class Exception and with message 'message'

Raise custom exception with extra constructor parameters by passing in an instance of the exception.

object = stub()
object.stubs(:expected_method).raises(MyException.new('message', 1, 2, 3))
object.expected_method # => raises the specified instance of MyException

Raise different exceptions on consecutive invocations of the expected method.

object = stub()
object.stubs(:expected_method).raises(Exception1).then.raises(Exception2)
object.expected_method # => raises exception of class Exception1
object.expected_method # => raises exception of class Exception2

Raise an exception on first invocation of expected method and then return values on subsequent invocations.

object = stub()
object.stubs(:expected_method).raises(Exception).then.returns(2, 3)
object.expected_method # => raises exception of class Exception1
object.expected_method # => 2
object.expected_method # => 3

Parameters:

  • exception (Class, Exception, String, #exception) (defaults to: RuntimeError)

    exception to be raised or message to be passed to RuntimeError.

  • message (String) (defaults to: nil)

    exception message.

Returns:

See Also:



413
414
415
416
# File 'lib/mocha/expectation.rb', line 413

def raises(exception = RuntimeError, message = nil)
  @return_values += ReturnValues.new(ExceptionRaiser.new(exception, message))
  self
end

#returns(value) ⇒ Expectation #returns(*values) ⇒ Expectation

Modifies expectation so that when the expected method is called, it returns the specified value.

Examples:

Return the same value on every invocation.

object = mock()
object.stubs(:stubbed_method).returns('result')
object.stubbed_method # => 'result'
object.stubbed_method # => 'result'

Return a different value on consecutive invocations.

object = mock()
object.stubs(:stubbed_method).returns(1, 2)
object.stubbed_method # => 1
object.stubbed_method # => 2

Alternative way to return a different value on consecutive invocations.

object = mock()
object.stubs(:expected_method).returns(1, 2).then.returns(3)
object.expected_method # => 1
object.expected_method # => 2
object.expected_method # => 3

May be called in conjunction with #raises on the same expectation.

object = mock()
object.stubs(:expected_method).returns(1, 2).then.raises(Exception)
object.expected_method # => 1
object.expected_method # => 2
object.expected_method # => raises exception of class Exception1

Note that in Ruby a method returning multiple values is exactly equivalent to a method returning an Array of those values.

object = mock()
object.stubs(:expected_method).returns([1, 2])
x, y = object.expected_method
x # => 1
y # => 2

Overloads:

  • #returns(value) ⇒ Expectation

    Parameters:

    • value (Object)

      value to return on invocation of expected method.

  • #returns(*values) ⇒ Expectation

    Parameters:

    • values (*Array)

      values to return on consecutive invocations of expected method.

Returns:

See Also:



373
374
375
376
# File 'lib/mocha/expectation.rb', line 373

def returns(*values)
  @return_values += ReturnValues.build(*values)
  self
end

#thenExpectation #then(state) ⇒ Expectation

Returns the same expectation, thereby allowing invocations of other Mocha::Expectation methods to be chained.

Examples:

Using #then as syntactic sugar when specifying values to be returned and exceptions to be raised on consecutive invocations of the expected method.

object = mock()
object.stubs(:expected_method).returns(1, 2).then.raises(Exception).then.returns(4)
object.expected_method # => 1
object.expected_method # => 2
object.expected_method # => raises exception of class Exception
object.expected_method # => 4

Using #then to change the state of a state_machine on the invocation of an expected method.

power = states('power').starts_as('off')

radio = mock('radio')
radio.expects(:switch_on).then(power.is('on'))
radio.expects(:select_channel).with('BBC Radio 4').when(power.is('on'))
radio.expects(:adjust_volume).with(+5).when(power.is('on'))
radio.expects(:select_channel).with('BBC World Service').when(power.is('on'))
radio.expects(:adjust_volume).with(-5).when(power.is('on'))
radio.expects(:switch_off).then(power.is('off'))

Overloads:

  • #thenExpectation

    Used as syntactic sugar to improve readability. It has no effect on state of the expectation.

  • #then(state) ⇒ Expectation

    Used to change the state_machine to the specified state when the expected invocation occurs.

    Parameters:

    • state (StateMachine::State)

      state_machine.is(state_name) provides a mechanism to change the state_machine into the state specified by state_name when the expected method is invoked.

    See Also:

Returns:



487
488
489
490
# File 'lib/mocha/expectation.rb', line 487

def then(state = nil)
  add_side_effect(ChangeStateSideEffect.new(state)) if state
  self
end

#throw(tag) ⇒ Expectation #throw(tag, object) ⇒ Expectation

Modifies expectation so that when the expected method is called, it throws the specified tag with the specific return value object i.e. calls Kernel#throw(tag, object).

Examples:

Throw tag when expected method is invoked.

object = stub()
object.stubs(:expected_method).throws(:done)
object.expected_method # => throws tag :done

Throw tag with return value object c.f. Kernel#throw.

object = stub()
object.stubs(:expected_method).throws(:done, 'result')
object.expected_method # => throws tag :done and causes catch block to return 'result'

Throw different tags on consecutive invocations of the expected method.

object = stub()
object.stubs(:expected_method).throws(:done).then.throws(:continue)
object.expected_method # => throws :done
object.expected_method # => throws :continue

Throw tag on first invocation of expected method and then return values for subsequent invocations.

object = stub()
object.stubs(:expected_method).throws(:done).then.returns(2, 3)
object.expected_method # => throws :done
object.expected_method # => 2
object.expected_method # => 3

Parameters:

  • tag (Symbol, String)

    tag to throw to transfer control to the active catch block.

  • object (Object) (defaults to: nil)

    return value for the catch block.

Returns:

See Also:



452
453
454
455
# File 'lib/mocha/expectation.rb', line 452

def throws(tag, object = nil)
  @return_values += ReturnValues.new(Thrower.new(tag, object))
  self
end

#times(range) ⇒ Expectation

Modifies expectation so that the number of calls to the expected method must be within a specific range.

Examples:

Specifying a specific number of expected invocations.

object = mock()
object.expects(:expected_method).times(3)
3.times { object.expected_method }
# => verify succeeds

object = mock()
object.expects(:expected_method).times(3)
2.times { object.expected_method }
# => verify fails

Specifying a range in the number of expected invocations.

object = mock()
object.expects(:expected_method).times(2..4)
3.times { object.expected_method }
# => verify succeeds

object = mock()
object.expects(:expected_method).times(2..4)
object.expected_method
# => verify fails

Parameters:

  • range (Range, Integer)

    specifies the allowable range in the number of expected invocations.

Returns:



44
45
46
47
# File 'lib/mocha/expectation.rb', line 44

def times(range)
  @cardinality.times(range)
  self
end

#twiceExpectation

Modifies expectation so that the expected method must be called exactly twice.

Examples:

Expected method must be invoked exactly twice.

object = mock()
object.expects(:expected_method).twice
object.expected_method
object.expected_method
# => verify succeeds

object = mock()
object.expects(:expected_method).twice
object.expected_method
object.expected_method
object.expected_method # => unexpected invocation

object = mock()
object.expects(:expected_method).twice
object.expected_method
# => verify fails

Returns:



70
71
72
73
# File 'lib/mocha/expectation.rb', line 70

def twice
  @cardinality.exactly(2)
  self
end

#when(state_predicate) ⇒ Expectation

Constrains the expectation to occur only when the state_machine is in the state specified by state_predicate.

Examples:

Using #when to only allow invocation of methods when “power” state machine is in the “on” state.

power = states('power').starts_as('off')

radio = mock('radio')
radio.expects(:switch_on).then(power.is('on'))
radio.expects(:select_channel).with('BBC Radio 4').when(power.is('on'))
radio.expects(:adjust_volume).with(+5).when(power.is('on'))
radio.expects(:select_channel).with('BBC World Service').when(power.is('on'))
radio.expects(:adjust_volume).with(-5).when(power.is('on'))
radio.expects(:switch_off).then(power.is('off'))

Parameters:

  • state_predicate (StateMachine::StatePredicate)

    state_machine.is(state_name) provides a mechanism to determine whether the state_machine is in the state specified by state_predicate when the expected method is invoked.

Returns:

See Also:



511
512
513
514
# File 'lib/mocha/expectation.rb', line 511

def when(state_predicate)
  add_ordering_constraint(InStateOrderingConstraint.new(state_predicate))
  self
end

#with(*expected_parameters) {|actual_parameters| ... } ⇒ Expectation

Modifies expectation so that the expected method must be called with expected_parameters.

May be used with parameter matchers in ParameterMatchers.

Examples:

Expected method must be called with expected parameters.

object = mock()
object.expects(:expected_method).with(:param1, :param2)
object.expected_method(:param1, :param2)
# => verify succeeds

object = mock()
object.expects(:expected_method).with(:param1, :param2)
object.expected_method(:param3)
# => verify fails

Expected method must be called with a value divisible by 4.

object = mock()
object.expects(:expected_method).with() { |value| value % 4 == 0 }
object.expected_method(16)
# => verify succeeds

object = mock()
object.expects(:expected_method).with() { |value| value % 4 == 0 }
object.expected_method(17)
# => verify fails

Parameters:

  • expected_parameters (*Array)

    parameters expected.

Yields:

  • optional block specifying custom matching.

Yield Parameters:

  • actual_parameters (*Array)

    parameters with which expected method was invoked.

Yield Returns:

  • (Boolean)

    true if actual_parameters are acceptable.

Returns:



221
222
223
224
# File 'lib/mocha/expectation.rb', line 221

def with(*expected_parameters, &matching_block)
  @parameters_matcher = ParametersMatcher.new(expected_parameters, &matching_block)
  self
end

#with_block_givenExpectation

Modifies expectation so that the expected method must be called with a block.

Examples:

Expected method must be called with a block.

object = mock()
object.expects(:expected_method).with_block_given
object.expected_method { 1 + 1 }
# => verify succeeds

object = mock()
object.expects(:expected_method).with_block_given
object.expected_method
# => verify fails

Returns:



240
241
242
243
# File 'lib/mocha/expectation.rb', line 240

def with_block_given
  @block_matcher = BlockMatchers::BlockGiven.new
  self
end

#with_no_block_givenExpectation

Modifies expectation so that the expected method must be called without a block.

Examples:

Expected method must be called without a block.

object = mock()
object.expects(:expected_method).with_no_block_given
object.expected_method
# => verify succeeds

object = mock()
object.expects(:expected_method).with_block_given
object.expected_method { 1 + 1 }
# => verify fails

Returns:



259
260
261
262
# File 'lib/mocha/expectation.rb', line 259

def with_no_block_given
  @block_matcher = BlockMatchers::NoBlockGiven.new
  self
end

#yields(*parameters) ⇒ Expectation

Modifies expectation so that when the expected method is called, it yields to the block with the specified parameters.

If no parameters are specified, it yields to the block without any parameters.

If no block is provided, the method will still attempt to yield resulting in a LocalJumpError. Note that this is what would happen if a “real” (non-mock) method implementation tried to yield to a non-existent block.

May be called multiple times on the same expectation for consecutive invocations.

Examples:

Yield when expected method is invoked.

benchmark = mock()
benchmark.expects(:measure).yields
yielded = false
benchmark.measure { yielded = true }
yielded # => true

Yield parameters when expected method is invoked.

fibonacci = mock()
fibonacci.expects(:next_pair).yields(0, 1)
sum = 0
fibonacci.next_pair { |first, second| sum = first + second }
sum # => 1

Yield different parameters on different invocations of the expected method.

fibonacci = mock()
fibonacci.expects(:next_pair).yields(0, 1).then.yields(1, 1)
sum = 0
fibonacci.next_pair { |first, second| sum = first + second }
sum # => 1
fibonacci.next_pair { |first, second| sum = first + second }
sum # => 2

Parameters:

  • parameters (*Array)

    parameters to be yielded.

Returns:

See Also:



298
299
300
# File 'lib/mocha/expectation.rb', line 298

def yields(*parameters)
  multiple_yields(parameters)
end