Flexible Mock
Hey, I've been posting too many abstract shit lately, how about some code?
So here's my simple Mock class and tests for it (to show how it works).
Class
class Mock
def initialize(method_name, block = nil )
block||=Proc.new do |*args|
args=args.first if args.length==1
yield(args)
end
self.class.send :define_method, method_name, block
end
end
Examples
class TestMock < MiniTest::Unit::TestCase
def test_mock
fake = Mock.new :some_method do
'value'
end
assert fake.some_method == 'value'
end
def test_mock_single_parameter
fake = Mock.new :some_method do |p|
p*2
end
assert_equal fake.some_method(2), 4
end
def test_mock_many_parameters
fake = Mock.new :some_method do |p1, p2, p3|
p1*p2*p3
end
assert_equal fake.some_method(2, 3, 4), 24
end
def test_lambda_parameter
fake = Mock.new :some_method, lambda {|p| p*2}
assert_equal fake.some_method(2), 4
end
def test_access_to_local_variable
p1=1
fake = Mock.new :some_method do
p1+=1
end
fake.some_method
assert_equal p1, 2
end
end
The problem with other mock libraries is that there's too much magic going on and syntax is tricky
mock.expect :method, 'return', [:params] ... mock.verify # or mock.should_receive(:method).with("A", 1, 3).onceIn more complex examples it gets hard to express what you want and remember syntax. I prefer more control, that's why my decision is to create object with custom method. In this method you can do whatever you want.
Another good thing of this approach is property of Proc to maintain context where it was called (look at the last example). This eliminates any need for internal verification via "mock.verify" since you can do it outside.
p.s. syntax highlighting I used can be found at github: highlight.js