Object
FlexMock is a flexible mock object framework for supporting testing.
FlexMock has a simple interface that’s easy to remember, and leaves the hard stuff to all those other mock object implementations.
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 include FlexMock::TestCase def test_something m = flexmock("name") m.should_receive(:hi).and_return("Hello") m.hi end end
Note: When using Test::Unit integeration, don’t forget to include FlexMock::TestCase. Also, if you override teardown, make sure you call super.
Deprecated Methods
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.
+++
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 55 55: def initialize(name="unknown", container=nil) 56: @flexmock_name = name 57: @expectations = Hash.new 58: @ignore_missing = false 59: @verified = false 60: container = UseContainer.new if container.nil? 61: container.flexmock_remember(self) 62: end
Undefined is normally available as FlexMock.undefined
# File lib/flexmock/undefined.rb, line 47 47: def self.undefined 48: @undefined 49: 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 39 39: def use(*names) 40: names = ["unknown"] if names.empty? 41: container = UseContainer.new 42: mocks = names.collect { |n| container.flexmock(n) } 43: yield(*mocks) 44: rescue Exception => _ 45: container.got_exception = true 46: raise 47: ensure 48: container.flexmock_teardown 49: end
# File lib/flexmock/core.rb, line 91 91: def by_default 92: @last_expectation.by_default 93: self 94: end
Create an alias for the existing method_name. Returns the new alias name. If the aliasing process fails (because the method doesn’t really exist, then return nil.
# File lib/flexmock/partial_mock.rb, line 236 236: def create_alias_for_existing_method(method_name) 237: begin 238: new_alias = new_name(method_name) 239: unless @obj.respond_to?(new_alias) 240: sclass.class_eval do 241: alias_method(new_alias, method_name) 242: end 243: end 244: new_alias 245: rescue NameError => _ 246: # Alias attempt failed 247: nil 248: end 249: end
Define a proxy method that forwards to our mock object. The proxy method is defined as a singleton method on the object being mocked.
# File lib/flexmock/partial_mock.rb, line 254 254: def define_proxy_method(method_name) 255: if method_name.to_s =~ /=$/ 256: eval_line = __LINE__ + 1 257: sclass.class_eval %{ 258: def #{method_name}(*args, &block) 259: instance_variable_get('@flexmock_proxy').mock.__send__(:#{method_name}, *args, &block) 260: end 261: }, __FILE__, eval_line 262: else 263: eval_line = __LINE__ + 1 264: sclass.class_eval %{ 265: def #{method_name}(*args, &block) 266: instance_variable_get('@flexmock_proxy').mock.#{method_name}(*args, &block) 267: end 268: }, __FILE__, eval_line 269: _ = true # make rcov recognize the above eval is covered 270: end 271: end
Have we been detached from the existing object?
# File lib/flexmock/partial_mock.rb, line 292 292: def detached? 293: @obj.nil? 294: 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 82 82: def flexmock_teardown 83: end
Verify that each method that had an explicit expected count was actually called that many times.
# File lib/flexmock/core.rb, line 71 71: def flexmock_verify 72: return if @verified 73: @verified = true 74: flexmock_wrap do 75: @expectations.each do |sym, handler| 76: handler.flexmock_verify 77: end 78: end 79: end
Hide the existing method definition with a singleton defintion that proxies to our mock object. If the current definition is a singleton, we need to record the definition and remove it before creating our own singleton method. If the current definition is not a singleton, all we need to do is override it with our own singleton.
# File lib/flexmock/partial_mock.rb, line 209 209: def hide_existing_method(method_name) 210: stow_existing_definition(method_name) 211: define_proxy_method(method_name) 212: end
Return the inspection string for a mock.
# File lib/flexmock/core.rb, line 65 65: def inspect 66: "<FlexMock:#{flexmock_name}>" 67: end
Override the built-in method to include the mocked methods.
# File lib/flexmock/core.rb, line 130 130: def method(sym) 131: @expectations[sym] || super 132: rescue NameError => ex 133: if @ignore_missing 134: proc { FlexMock.undefined } 135: else 136: raise ex 137: end 138: end
Handle missing methods by attempting to look up a handler.
# File lib/flexmock/core.rb, line 97 97: def method_missing(sym, *args, &block) 98: flexmock_wrap do 99: if handler = @expectations[sym] 100: args << block if block_given? 101: handler.call(*args) 102: elsif @ignore_missing 103: FlexMock.undefined 104: else 105: super(sym, *args, &block) 106: end 107: end 108: end
Generate a name to be used to alias the original behavior.
# File lib/flexmock/partial_mock.rb, line 297 297: def new_name(old_name) 298: "flexmock_original_behavior_for_#{old_name}" 299: end
Remove the current method if it is a singleton method of the object being mocked.
# File lib/flexmock/partial_mock.rb, line 287 287: def remove_current_method(method_name) 288: sclass.class_eval { remove_method(method_name) } 289: end
Override the built-in respond_to? to include the mocked methods.
# File lib/flexmock/core.rb, line 114 114: def respond_to?(sym, *args) 115: super || (@expectations[sym] ? true : @ignore_missing) 116: end
Restore the original singleton defintion for method_name that was saved earlier.
# File lib/flexmock/partial_mock.rb, line 275 275: def restore_original_definition(method_name) 276: method_def = @method_definitions[method_name] 277: if method_def 278: the_alias = new_name(method_name) 279: sclass.class_eval do 280: alias_method(method_name, the_alias) 281: end 282: end 283: 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 182 182: def should_expect 183: yield Recorder.new(self) 184: end
Ignore all undefined (missing) method calls.
# File lib/flexmock/core.rb, line 86 86: def should_ignore_missing 87: @ignore_missing = true 88: 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 159 159: def should_receive(*args) 160: @last_expectation = ContainerHelper.parse_should_args(self, args) do |sym| 161: @expectations[sym] ||= ExpectationDirector.new(sym) 162: result = Expectation.new(self, sym) 163: @expectations[sym] << result 164: override_existing_method(sym) if flexmock_respond_to?(sym) 165: result 166: end 167: @last_expectation 168: end
Is the given method name a singleton method in the object we are mocking?
# File lib/flexmock/partial_mock.rb, line 199 199: def singleton?(method_name) 200: @obj.methods(false).include?(method_name.to_s) 201: end
Stow the existing method definition so that it can be recovered later.
# File lib/flexmock/partial_mock.rb, line 216 216: def stow_existing_definition(method_name) 217: @methods_proxied << method_name 218: new_alias = create_alias_for_existing_method(method_name) 219: if new_alias 220: my_object = @obj 221: @method_definitions[method_name] = Proc.new { |*args| 222: block = nil 223: if Proc === args.last 224: block = args.last 225: args = args[0...1] 226: end 227: my_object.send(new_alias, *args, &block) 228: } 229: end 230: remove_current_method(method_name) if singleton?(method_name) 231: end
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 190 190: def flexmock_wrap(&block) 191: yield 192: rescue FlexMock.framework_adapter.assertion_failed_error => ex 193: raise FlexMock.framework_adapter.assertion_failed_error, 194: "in mock '#{@flexmock_name}': #{ex.message}", 195: ex.backtrace 196: end
Override the existing definition of method sym 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 204 204: def override_existing_method(sym) 205: sclass.class_eval def #{sym}(*args, &block) method_missing(:#{sym}, *args, &block) end 206: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.