class FlexMock

+

+

FlexMock is a flexible mock object framework for creating and using test doubles (mocks, stubs and spies).

Basic Usage:

m = flexmock("name")
m.should_receive(:upcase).with("stuff").
  and_return("STUFF")
m.should_receive(:downcase).with(String).
  and_return { |s| s.downcase }.once

With Test::Unit Integration:

class TestSomething < Test::Unit::TestCase
  def test_something
    m = flexmock("name")
    m.should_receive(:hi).and_return("Hello")
    m.hi
  end
end

Note: Also, if you override teardown, make sure you call super.

Deprecated Methods

The following methods are no longer supported in FlexMock. Include this file for legacy applications.

Permission is granted for use, copying, modification, distribution,
and distribution of modified versions of this work as long as the
above copyright notice is included.

+++

Permission is granted for use, copying, modification, distribution,
and distribution of modified versions of this work as long as the
above copyright notice is included.

+++

Permission is granted for use, copying, modification, distribution,
and distribution of modified versions of this work as long as the
above copyright notice is included.

+++

Permission is granted for use, copying, modification, distribution,
and distribution of modified versions of this work as long as the
above copyright notice is included.

+++

Constants

ANY
CALL_VALIDATOR
CONTAINER_HELPER
CallRecord
EXP_BUILDER
FORBID_MOCKING
ON_RUBY_20
OPTIONAL_PROC_MATCHER
SpecModule
VERSION

Attributes

framework_adapter[R]
partials_are_based[RW]
partials_verify_signatures[RW]
flexmock_container_stack[R]
flexmock_name[R]

Public Class Methods

forbid_mocking(mocking_forbidden_return = nil) { || ... } click to toggle source

Forbid mock calls to happen while the block is being evaluated

@param [Object] mocking_forbidden_return the return value that should be

used if a mocking call has happened. If no mocking calls happened,
returns the return value of the block
# File lib/flexmock/core_class_methods.rb, line 58
def forbid_mocking(mocking_forbidden_return = nil)
  current, Thread.current[FORBID_MOCKING] =
      Thread.current[FORBID_MOCKING], true

  catch(FORBID_MOCKING) do
    return yield
  end
  mocking_forbidden_return

ensure
  Thread.current[FORBID_MOCKING] = current
end
format_args(args) click to toggle source

Class method to format a list of args (the part between the parenthesis).

# File lib/flexmock/core_class_methods.rb, line 87
def format_args(args)
  if args
    args = args.map do |a|
      FlexMock.forbid_mocking("<recursive call to mocked method in #inspect>") do
        a.inspect
      end
    end
    args.join(', ')
  else
    "*args"
  end
end
new(name="unknown", container=nil, parent: nil) click to toggle source

Create a FlexMock object with the given name. The name is used in error messages. If no container is given, create a new, one-off container for this mock.

# File lib/flexmock/core.rb, line 66
def initialize(name="unknown", container=nil, parent: nil)
  @flexmock_name = name
  @flexmock_closed = false
  @flexmock_container_stack = Array.new
  @expectations = Hash.new
  @verified = false
  @calls = []
  @base_class = nil
  if parent
    @ignore_missing = parent.ignore_missing?
    @parent_mock = parent
  else
    @ignore_missing = false
    @parent_mock = NullParentMock.new
  end
  container = UseContainer.new if container.nil?
  container.flexmock_remember(self)
end
undefined() click to toggle source

Undefined is normally available as ::undefined

# File lib/flexmock/undefined.rb, line 47
def self.undefined
  @undefined
end
use(*names) { |*mocks| ... } click to toggle source

Class method to make sure that verify is called at the end of a test. One mock object will be created for each name given to the use method. The mocks will be passed to the block as arguments. If no names are given, then a single anonymous mock object will be created.

At the end of the use block, each mock object will be verified to make sure the proper number of calls have been made.

Usage:

FlexMock.use("name") do |mock|    # Creates a mock named "name"
  mock.should_receive(:meth).
    returns(0).once
end                               # mock is verified here

NOTE: If you include FlexMock::TestCase into your test case file, you can create mocks that will be automatically verified in the test teardown by using the flexmock method.

# File lib/flexmock/core_class_methods.rb, line 39
def use(*names)
  names = ["unknown"] if names.empty?
  container = UseContainer.new
  mocks = names.collect { |n| container.flexmock(n) }
  yield(*mocks)
rescue Exception => _
  container.got_exception = true
  raise
ensure
  container.flexmock_teardown
end
verify_mocking_allowed!() click to toggle source

Verify that mocking is allowed in the current context. Throws if it is not.

# File lib/flexmock/core_class_methods.rb, line 73
def verify_mocking_allowed!
  if Thread.current[FORBID_MOCKING]
    throw FORBID_MOCKING
  end
end

Public Instance Methods

by_default() click to toggle source
# File lib/flexmock/core.rb, line 134
def by_default
  @last_expectation.by_default
  self
end
flexmock_base_class() click to toggle source
# File lib/flexmock/core.rb, line 181
def flexmock_base_class
  @base_class
end
flexmock_based_on(base_class) click to toggle source
# File lib/flexmock/core.rb, line 185
def flexmock_based_on(base_class)
  @base_class = base_class
  if base_class <= Kernel
    if self.class != base_class
      should_receive(:class => base_class)
      should_receive(:kind_of?).and_return { |against| base_class <= against }
    end
  end
end
flexmock_calls() click to toggle source

Return the list of calls made on this mock. Used in formatting error messages.

# File lib/flexmock/core.rb, line 204
def flexmock_calls
  @calls
end
flexmock_closed?() click to toggle source
# File lib/flexmock/core.rb, line 123
def flexmock_closed?
  @flexmock_closed
end
flexmock_container() click to toggle source
# File lib/flexmock/core.rb, line 89
def flexmock_container
  flexmock_container_stack.last
end
flexmock_define_expectation(location, *args) click to toggle source

Using location, define the expectations specified by args.

# File lib/flexmock/core.rb, line 251
def flexmock_define_expectation(location, *args)
  @last_expectation = EXP_BUILDER.parse_should_args(self, args) do |method_name|
    exp = flexmock_expectations_for(method_name) || ExpectationDirector.new(method_name)
    @expectations[method_name] = exp
    result = Expectation.new(self, method_name, location)
    exp << result
    override_existing_method(method_name) if flexmock_respond_to?(method_name, true)

    if @base_class && !@base_class.flexmock_defined?(method_name)
      if !ON_RUBY_20 || !@base_class.ancestors.include?(Class)
        result = ExplicitNeeded.new(result, method_name, @base_class) 
      end
    end
    result
  end
end
flexmock_invoke_original(method_name, args) click to toggle source

Invocke the original non-mocked functionality for the given symbol.

# File lib/flexmock/core.rb, line 210
def flexmock_invoke_original(method_name, args)
  return FlexMock.undefined
end
flexmock_received?(method_name, args, options={}) click to toggle source

True if the mock received the given method and arguments.

# File lib/flexmock/core.rb, line 198
def flexmock_received?(method_name, args, options={})
  CALL_VALIDATOR.received?(@calls, method_name, args, options)
end
flexmock_respond_to?(sym, *args)

Save the original definition of respond_to? for use a bit later.

Alias for: respond_to?
flexmock_teardown() click to toggle source

Teardown and infrastructure setup for this mock.

# File lib/flexmock/core.rb, line 119
def flexmock_teardown
  @flexmock_closed = true
end
flexmock_verify() click to toggle source

Verify that each method that had an explicit expected count was actually called that many times.

# File lib/flexmock/core.rb, line 108
def flexmock_verify
  return if @verified
  @verified = true
  flexmock_wrap do
    @expectations.each do |sym, handler|
      handler.flexmock_verify
    end
  end
end
ignore_missing?() click to toggle source
# File lib/flexmock/core.rb, line 85
def ignore_missing?
  @ignore_missing
end
inspect() click to toggle source

Return the inspection string for a mock.

# File lib/flexmock/core.rb, line 102
def inspect
  "<FlexMock:#{flexmock_name}>"
end
method(method_name) click to toggle source

Override the built-in method to include the mocked methods.

Calls superclass method
# File lib/flexmock/core.rb, line 215
def method(method_name)
  flexmock_expectations_for(method_name) || super
rescue NameError => ex
  if ignore_missing?
    proc { FlexMock.undefined }
  else
    raise ex
  end
end
method_missing(sym, *args, &block) click to toggle source

Handle missing methods by attempting to look up a handler.

Calls superclass method
# File lib/flexmock/core.rb, line 140
def method_missing(sym, *args, &block)
  FlexMock.verify_mocking_allowed!

  enhanced_args = block_given? ? args + [block] : args
  call_record = CallRecord.new(sym, enhanced_args, block_given?)
  @calls << call_record
  flexmock_wrap do
    if flexmock_closed?
      FlexMock.undefined
    elsif exp = flexmock_expectations_for(sym)
      exp.call(enhanced_args, call_record)
    elsif @base_class && @base_class.flexmock_defined?(sym)
      FlexMock.undefined
    elsif @ignore_missing
      FlexMock.undefined
    else
      super(sym, *args, &block)
    end
  end
end
mock_ignore_missing()
pop_flexmock_container() click to toggle source
# File lib/flexmock/core.rb, line 97
def pop_flexmock_container
  flexmock_container_stack.pop
end
push_flexmock_container(container) click to toggle source
# File lib/flexmock/core.rb, line 93
def push_flexmock_container(container)
  flexmock_container_stack.push(container)
end
respond_to?(sym, *args) click to toggle source

Override the built-in respond_to? to include the mocked methods.

Calls superclass method
# File lib/flexmock/core.rb, line 165
def respond_to?(sym, *args)
  super || (@expectations[sym] ? true : @ignore_missing)
end
Also aliased as: flexmock_respond_to?
should_expect() { |recorder| ... } click to toggle source

Declare that the mock object should expect methods by providing a recorder for the methods and having the user invoke the expected methods in a block. Further expectations may be applied the result of the recording call.

Example Usage:

mock.should_expect do |record|
  record.add(Integer, 4) { |a, b|
    a + b
  }.at_least.once
# File lib/flexmock/core.rb, line 280
def should_expect
  yield Recorder.new(self)
end
should_ignore_missing() click to toggle source

Ignore all undefined (missing) method calls.

# File lib/flexmock/core.rb, line 128
def should_ignore_missing
  @ignore_missing = true
  self
end
Also aliased as: mock_ignore_missing
should_receive(:method_name) click to toggle source
should_receive(:method1, method2, ...)
should_receive(:meth1 => result1, :meth2 → result2, ...)

Declare that the mock object should receive a message with the given name.

If more than one method name is given, then the mock object should expect to receive all the listed melthods. If a hash of method name/value pairs is given, then the each method will return the associated result. Any expectations applied to the result of should_receive will be applied to all the methods defined in the argument list.

An expectation object for the method name is returned as the result of this method. Further expectation constraints can be added by chaining to the result.

See Expectation for a list of declarators that can be used.

# File lib/flexmock/core.rb, line 244
def should_receive(*args)
  flexmock_define_expectation(caller, *args)
end

Private Instance Methods

flexmock_wrap() { || ... } click to toggle source

Wrap a block of code so the any assertion errors are wrapped so that the mock name is added to the error message .

# File lib/flexmock/core.rb, line 288
def flexmock_wrap(&block)
  yield
rescue FlexMock.framework_adapter.assertion_failed_error, FlexMock.framework_adapter.check_failed_error => ex
  raise ex, "in mock '#{@flexmock_name}': #{ex.message}", ex.backtrace
end
override_existing_method(method_name) click to toggle source

Override the existing definition of method method_name in the mock. Most methods depend on the #method_missing trick to be invoked. However, if the method already exists, it will not call method_missing. This method defines a singleton method on the mock to explicitly invoke the #method_missing logic.

# File lib/flexmock/core.rb, line 299
def override_existing_method(method_name)
  sclass.class_eval <<-EOS
    def #{method_name}(*args, &block)
      method_missing(:#{method_name}, *args, &block)
    end
  EOS
end
sclass() click to toggle source

Return the singleton class of the mock object.

# File lib/flexmock/core.rb, line 308
def sclass
  class << self; self; end
end