mock.rb

Copyright © 2005 George Moschovitis, Michael Granger

  Ruby License

  This module is free software. You may use, modify, and/or redistribute this
  software under the same terms as Ruby.

  This program is distributed in the hope that it will be useful, but WITHOUT
  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  FOR A PARTICULAR PURPOSE.

Special Thanks

Thanks goes to Michael Granger for Test::Unit::Mock on which this library is partially based.

Author(s)

  • Thomas Sawyer

Developer Notes

  TODO Rename to MockObject ?
       Should this be under Test::Unit too ?
Required Files
Methods
Public Instance methods
Mock( realclass )

Factory method for creating semi-functional mock objects given the class which is to be mocked. It looks like a constant for purposes of syntactic sugar.

# File lib/facets/more/mock.rb, line 148
def Mock( realclass )

  mockclass = Class.new( Mock )

  mockclass.instance_eval do @mocked_class = realclass end

  # Provide an accessor to class instance var that holds the class
  # object we're faking
  class << mockclass
    # The actual class being mocked
    attr_reader :mocked_class

    # Propagate the mocked class ivar to derivatives so it can be
    # called like:
    #   class MockFoo < Mock( RealClass )
    def inherited( subclass )
      mc = self.mockedClass
      subclass.instance_eval do @mocked_class = mc end
    end
  end

  # Build method definitions for all the mocked class's instance
  # methods, as well as those given to it by its superclasses, since
  # we're not really inheriting from it.
  imethods = realclass.instance_methods(true).collect do |name|
    next if name =~ ::Mock::UnmockedMethods

    # Figure out the argument list
    arity = realclass.instance_method( name ).arity
    optargs = false

    if arity < 0
      optargs = true
      arity = (arity+1).abs
    end

    args = []
    arity.times do |n| args << "arg#{n+1}" end
    args << "*optargs" if optargs

    # Build a method definition. Some methods need special
    # declarations.
    argsj = args.join(',')
    case name.intern
    when :initialize
      "def initialize(#{argsj}) ; super ; end"
    else
      "def #{name}(#{argsj}) ; self.send(#{name},#{argsj}) ; end"
      #"def %s( %s ) ; self.__mockRegisterCall(%s) ; end" %
      #  [ name, argstr, [":#{name}", *args].join(',') ]
    end
  end

  # Now add the instance methods to the mockclass class
  mockclass.class_eval imethods.join( "\n" )

  return mockclass
end