Class: Mocha::Mock

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

Overview

Traditional mock object.

All methods return an Expectation which can be further modified by methods on Expectation.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(mockery, name = nil, &block) ⇒ Mock



165
166
167
168
169
170
171
172
# File 'lib/mocha/mock.rb', line 165

def initialize(mockery, name = nil, &block)
  @mockery = mockery
  @name = name || DefaultName.new(self)
  @expectations = ExpectationList.new
  @everything_stubbed = false
  @responder = nil
  instance_eval(&block) if block
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(symbol, *arguments, &block) ⇒ Object



194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
# File 'lib/mocha/mock.rb', line 194

def method_missing(symbol, *arguments, &block)
  if @responder and not @responder.respond_to?(symbol)
    raise NoMethodError, "undefined method `#{symbol}' for #{self.mocha_inspect} which responds like #{@responder.mocha_inspect}"
  end
  if matching_expectation_allowing_invocation = @expectations.match_allowing_invocation(symbol, *arguments)
    matching_expectation_allowing_invocation.invoke(&block)
  else
    if (matching_expectation = @expectations.match(symbol, *arguments)) || (!matching_expectation && !@everything_stubbed)
      matching_expectation.invoke(&block) if matching_expectation
      message = UnexpectedInvocation.new(self, symbol, *arguments).to_s
      message << @mockery.mocha_inspect
      raise ExpectationError.new(message, caller)
    end
  end
end

Instance Attribute Details

#everything_stubbedObject (readonly)



175
176
177
# File 'lib/mocha/mock.rb', line 175

def everything_stubbed
  @everything_stubbed
end

Instance Method Details

#__expectations__Object



184
185
186
# File 'lib/mocha/mock.rb', line 184

def __expectations__
  @expectations
end

#__verified__?(assertion_counter = nil) ⇒ Boolean



224
225
226
# File 'lib/mocha/mock.rb', line 224

def __verified__?(assertion_counter = nil)
  @expectations.verified?(assertion_counter)
end

#any_expectations?Boolean



244
245
246
# File 'lib/mocha/mock.rb', line 244

def any_expectations?
  @expectations.any?
end

#ensure_method_not_already_defined(method_name) ⇒ Object



239
240
241
# File 'lib/mocha/mock.rb', line 239

def ensure_method_not_already_defined(method_name)
  self.__metaclass__.send(:undef_method, method_name) if self.__metaclass__.method_defined?(method_name)
end

#expects(method_name) ⇒ Expectation #expects(expected_methods_vs_return_values) ⇒ Expectation Also known as: __expects__

Adds an expectation that the specified method must be called exactly once with any parameters.

Examples:

Expected method invoked once so no error raised

object = mock()
object.expects(:expected_method)
object.expected_method

Expected method not invoked so error raised

object = mock()
object.expects(:expected_method)
# error raised when test completes, because expected_method not called exactly once

Expected method invoked twice so error raised

object = mock()
object.expects(:expected_method)
object.expected_method
object.expected_method # => error raised when expected method invoked second time

Setup multiple expectations using expected_methods_vs_return_values.

object = mock()
object.expects(:expected_method_one => :result_one, :expected_method_two => :result_two)

# is exactly equivalent to

object = mock()
object.expects(:expected_method_one).returns(:result_one)
object.expects(:expected_method_two).returns(:result_two)


51
52
53
54
55
56
57
58
59
60
# File 'lib/mocha/mock.rb', line 51

def expects(method_name_or_hash, backtrace = nil)
  iterator = ArgumentIterator.new(method_name_or_hash)
  iterator.each { |*args|
    method_name = args.shift
    ensure_method_not_already_defined(method_name)
    expectation = Expectation.new(self, method_name, backtrace)
    expectation.returns(args.shift) if args.length > 0
    @expectations.add(expectation)
  }
end

#inspectObject



234
235
236
# File 'lib/mocha/mock.rb', line 234

def inspect
  mocha_inspect
end

#mocha_inspectObject



229
230
231
# File 'lib/mocha/mock.rb', line 229

def mocha_inspect
  @name.mocha_inspect
end

#respond_to?(symbol, include_private = false) ⇒ Boolean



211
212
213
214
215
216
217
218
219
220
221
# File 'lib/mocha/mock.rb', line 211

def respond_to?(symbol, include_private = false)
  if @responder then
    if @responder.method(:respond_to?).arity > 1
      @responder.respond_to?(symbol, include_private)
    else
      @responder.respond_to?(symbol)
    end
  else
    @everything_stubbed || @expectations.matches_method?(symbol)
  end
end

#responds_like(responder) ⇒ Mock Also known as: quacks_like

Constrains the Mocha::Mock instance so that it can only expect or stub methods to which responder responds. The constraint is only applied at method invocation time.

A NoMethodError will be raised if the responder does not #respond_to? a method invocation (even if the method has been expected or stubbed).

The Mocha::Mock instance will delegate its #respond_to? method to the responder.

Examples:

Normal mocking

sheep = mock('sheep')
sheep.expects(:chew)
sheep.expects(:foo)
sheep.respond_to?(:chew) # => true
sheep.respond_to?(:foo) # => true
sheep.chew
sheep.foo
# no error raised

Using #responds_like with an instance method

class Sheep
  def chew(grass); end
end

sheep = mock('sheep')
sheep.responds_like(Sheep.new)
sheep.expects(:chew)
sheep.expects(:foo)
sheep.respond_to?(:chew) # => true
sheep.respond_to?(:foo) # => false
sheep.chew
sheep.foo # => raises NoMethodError exception

Using #responds_like with a class method

class Sheep
  def self.number_of_legs; end
end

sheep_class = mock('sheep_class')
sheep_class.responds_like(Sheep)
sheep_class.stubs(:number_of_legs).returns(4)
sheep_class.expects(:foo)
sheep_class.respond_to?(:number_of_legs) # => true
sheep_class.respond_to?(:foo) # => false
assert_equal 4, sheep_class.number_of_legs
sheep_class.foo # => raises NoMethodError exception


159
160
161
162
# File 'lib/mocha/mock.rb', line 159

def responds_like(responder)
  @responder = responder
  self
end

#stub_everythingObject



189
190
191
# File 'lib/mocha/mock.rb', line 189

def stub_everything
  @everything_stubbed = true
end

#stubs(method_name) ⇒ Expectation #stubs(stubbed_methods_vs_return_values) ⇒ Expectation Also known as: __stubs__

Adds an expectation that the specified method may be called any number of times with any parameters.

Examples:

No error raised however many times stubbed method is invoked

object = mock()
object.stubs(:stubbed_method)
object.stubbed_method
object.stubbed_method
# no error raised

Setup multiple expectations using stubbed_methods_vs_return_values.

object = mock()
object.stubs(:stubbed_method_one => :result_one, :stubbed_method_two => :result_two)

# is exactly equivalent to

object = mock()
object.stubs(:stubbed_method_one).returns(:result_one)
object.stubs(:stubbed_method_two).returns(:result_two)


87
88
89
90
91
92
93
94
95
96
97
# File 'lib/mocha/mock.rb', line 87

def stubs(method_name_or_hash, backtrace = nil)
  iterator = ArgumentIterator.new(method_name_or_hash)
  iterator.each { |*args|
    method_name = args.shift
    ensure_method_not_already_defined(method_name)
    expectation = Expectation.new(self, method_name, backtrace)
    expectation.at_least(0)
    expectation.returns(args.shift) if args.length > 0
    @expectations.add(expectation)
  }
end

#unstub(method_name) ⇒ Object

Removes the specified stubbed method (added by calls to #expects or #stubs) and all expectations associated with it.

Examples:

Invoking an unstubbed method causes error to be raised

object = mock('mock') do
object.stubs(:stubbed_method).returns(:result_one)
object.stubbed_method # => :result_one
object.unstub(:stubbed_method)
object.stubbed_method # => unexpected invocation: #<Mock:mock>.stubbed_method()


109
110
111
# File 'lib/mocha/mock.rb', line 109

def unstub(method_name)
  @expectations.remove_all_matching_method(method_name)
end