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
Public Class Methods
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 57 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
Class
method to format a list of args (the part between the parenthesis).
# File lib/flexmock/core_class_methods.rb, line 86 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
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 65 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
is normally available as FlexMock.undefined
# File lib/flexmock/undefined.rb, line 46 def self.undefined @undefined end
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 38 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 that mocking is allowed in the current context. Throws if it is not.
# File lib/flexmock/core_class_methods.rb, line 72 def verify_mocking_allowed! if Thread.current[FORBID_MOCKING] throw FORBID_MOCKING end end
Public Instance Methods
# File lib/flexmock/core.rb, line 133 def by_default @last_expectation.by_default self end
# File lib/flexmock/core.rb, line 180 def flexmock_base_class @base_class end
# File lib/flexmock/core.rb, line 184 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
Return the list of calls made on this mock. Used in formatting error messages.
# File lib/flexmock/core.rb, line 203 def flexmock_calls @calls end
# File lib/flexmock/core.rb, line 122 def flexmock_closed? @flexmock_closed end
# File lib/flexmock/core.rb, line 88 def flexmock_container flexmock_container_stack.last end
Using location
, define the expectations specified by args
.
# File lib/flexmock/core.rb, line 250 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
Invocke the original non-mocked functionality for the given symbol.
# File lib/flexmock/core.rb, line 209 def flexmock_invoke_original(method_name, args) return FlexMock.undefined end
True if the mock received the given method and arguments.
# File lib/flexmock/core.rb, line 197 def flexmock_received?(method_name, args, options={}) CALL_VALIDATOR.received?(@calls, method_name, args, options) end
Save the original definition of respond_to? for use a bit later.
Teardown and infrastructure setup for this mock.
# File lib/flexmock/core.rb, line 118 def flexmock_teardown @flexmock_closed = true end
Verify that each method that had an explicit expected count was actually called that many times.
# File lib/flexmock/core.rb, line 107 def flexmock_verify return if @verified @verified = true flexmock_wrap do @expectations.each do |sym, handler| handler.flexmock_verify end end end
# File lib/flexmock/core.rb, line 84 def ignore_missing? @ignore_missing end
Return the inspection string for a mock.
# File lib/flexmock/core.rb, line 101 def inspect "<FlexMock:#{flexmock_name}>" end
Override the built-in method
to include the mocked methods.
# File lib/flexmock/core.rb, line 214 def method(method_name) flexmock_expectations_for(method_name) || super rescue NameError => ex if ignore_missing? proc { FlexMock.undefined } else raise ex end end
Handle missing methods by attempting to look up a handler.
# File lib/flexmock/core.rb, line 139 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
# File lib/flexmock/core.rb, line 96 def pop_flexmock_container flexmock_container_stack.pop end
# File lib/flexmock/core.rb, line 92 def push_flexmock_container(container) flexmock_container_stack.push(container) end
Override the built-in respond_to? to include the mocked methods.
# File lib/flexmock/core.rb, line 164 def respond_to?(sym, *args) super || (@expectations[sym] ? true : @ignore_missing) end
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 279 def should_expect yield Recorder.new(self) end
Ignore all undefined (missing) method calls.
# File lib/flexmock/core.rb, line 127 def should_ignore_missing @ignore_missing = true self end
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 243 def should_receive(*args) flexmock_define_expectation(caller, *args) end
Private Instance Methods
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 287 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 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 298 def override_existing_method(method_name) sclass.class_eval <<-EOS def #{method_name}(*args, &block) method_missing(:#{method_name}, *args, &block) end EOS end
Return the singleton class of the mock object.
# File lib/flexmock/core.rb, line 307 def sclass class << self; self; end end