|
|
require 'class_constants'
class Class
def mock(klass, method_name, new_method_body)
@mocked_classes ||= []
@mocked_classes << klass
mock_class = Class.new(klass)
mock_class.class_eval(%Q{
def #{method_name.to_s}(*args)
#{new_method_body}
end})
set_constant(klass.name, mock_class)
end
def unmock
@mocked_classes.each do |klass|
set_constant(klass.name, klass)
end
end
end
unit_test do
class Engine
attr_reader :num_of_cylinders
def initialize(num_of_cylinders)
@num_of_cylinders = num_of_cylinders
end
def speed
44
end
end
class Car
def initialize
@engine = Engine.new(6)
end
def speed
@engine.speed
end
def num_of_cylinders
@engine.num_of_cylinders
end
end
class ClassMockTest < Test::Unit::TestCase
def test_mocking
Car.mock(Engine, :speed, 24)
assert_equal(24, Car.new.speed)
assert_equal(6, Car.new.num_of_cylinders)
assert_equal(44, Engine.new(4).speed) # only effects references inside the class 'Car'
Car.unmock
end
def test_unmocking
Car.mock(Engine, :speed, 24)
assert_equal(24, Car.new.speed)
Car.unmock
assert_equal(44, Car.new.speed)
end
end
end
#
# class_constants.rb
#
class Class
def get_constant(constant_name)
namespace_segments(constant_name).inject(self) { |scope, name| scope.const_get(name) }
end
def set_constant(constant_name, value)
namespaces = namespace_segments(constant_name)
if namespaces.size > 1
context = get_constant(namespaces[0..-2].join)
context.const_set(namespaces[-1], value)
else
self.const_set(constant_name, value)
end
end
def namespace_segments(name)
name.sub(/^::/,'').split("::")
end
end
unit_test do
module A
class One
end
end
class Two
def self.value
"the number two"
end
end
class Three
def self.value
"the number three"
end
end
class ClassConstantsTest < Test::Unit::TestCase
def test_get_constant
assert_equal(A::One, self.class.get_constant('A::One'))
end
def test_set_constant
new_class = Class.new
assert_nothing_raised{self.class.set_constant('A::One', new_class)}
assert_equal(new_class, self.class.get_constant('A::One'))
assert_nothing_raised{self.class.set_constant('Two', Three)}
assert_equal(Three.value, self.class.get_constant('Two').value)
end
def test_const_set
self.class.const_set('Const1', 1)
assert_equal(1, Const1)
class1 = Class.new
class2 = Class.new
self.class.const_set('Const2', class1)
assert_equal(class1, Const2)
self.class.const_set('Const2', class2)
assert_equal(class2, Const2)
class3 = Class.new
self.class.const_set('Const3', class3)
Const3.const_set('Const2', class1)
assert_equal(class1, Const3::Const2)
assert_equal(class2, Const2)
assert_equal(class2, Const2.new.class)
assert_equal(class1, Const3::Const2.new.class)
Const3.const_set('Const2', class2)
assert_equal(class2, Const3::Const2.new.class)
end
module Module1
class Class1
end
end
class Class2
attr_reader :var1
def initialize
@var1 = Module1::Class1.new
end
end
class Class1a
end
def test_constant_resolution
original_class1 = Module1::Class1
assert_equal(Module1::Class1, Class2.new.var1.class)
Module1.const_set('Class1', Class1a)
assert_equal(Class1a, Class2.new.var1.class)
assert_equal("ClassConstantsTest::Module1::Class1", original_class1.name)
Module1.const_set('Class1', original_class1)
assert_equal(Module1::Class1, Class2.new.var1.class)
class1b = Class.new
Module1.const_set('Class1', class1b)
assert_equal(class1b, Class2.new.var1.class)
assert_equal("ClassConstantsTest::Module1::Class1", class1b.name)
assert_equal("ClassConstantsTest::Module1::Class1", original_class1.name)
end
end
end
|