Reputation: 135187
Interacting directly with brains is not easy, so I have a little Gateway Pattern in use with some Dependency Inversion.
NumberCruncher
is a wrapper for my Brain
class.
class NumberCruncher
def initialize brain = Brain.new
@brain = brain
end
def times_one_hundred *numbers
numbers.map &@brain.method(:multiply_by_100)
end
end
I'm getting an error when testing though:
NameError: undefined method `multiply_by_100' for class `Mocha::Mock'
Here's the test
class NumberCruncherTest
def setup
@brain = mock
@cruncher = NumberCruncher.new @brain
end
def test_times_one_hundred
@brain.expects(:multiply_by_100).with(1).returns(100)
@brain.expects(:multiply_by_100).with(2).returns(200)
@brain.expects(:multiply_by_100).with(3).returns(300)
assert_equal [100, 200, 300], @cruncher.times_one_hundred(1,2,3)
end
end
I'm assuming it's because of the &@brain.method(:multiply_by_100)
call and mocha works by using method_missing
or something. The only solution seems to be to change the setup
class NumberCruncherTest
class FakeBrain
def multiply_by_100; end
end
def setup
@brain = FakeBrain.new
@cruncher = NumberCruncher.new @brain
end
# ...
end
However, I think this solution kind of sucks. It gets messy fast and it putting tons of Fake*
classes all over my tests. Is there any better way to do this with mocha?
Upvotes: 1
Views: 1245
Reputation: 16710
I think you can fix your problem by changing your method.
from
numbers.map &@brain.method(:multiply_by_100)
# which is equivalent to (just to understand the rest of my answer)
numbers.map {|number| @brain.method(:multiply_by_100).to_proc.call(number) }
to
numbers.map {|number| @brain.send(:multiply_by_100, number) }
This is actually better because there are some issues with your code. Transforming an object method into a proc (as you are doing), kinda freezes the state of your object into the proc and so any changes on instance variables will not take effect, and probably it's slower. send
should work fine on your case, and works with any mocking framework.
Btw, my guess on why your test does not work it's because mocha does not stub proc methods, and for good, because if you transform a method into a proc, you are not testing a method call anymore but a proc call.
And because everyone loves benchmarks:
@o = Object.new
def with_method_to_proc
@o.method(:to_s).to_proc.call
end
def with_send
@o.send(:to_s)
end
def bench(n)
s=Time.new
n.times { yield }
e=Time.new
e-s
end
bench(100) { with_method_to_proc }
# => 0.000252
bench(100) { with_send }
# => 0.000106
bench(1000) { with_method_to_proc }
# => 0.004398
bench(1000) { with_send }
# => 0.001402
bench(1000000) { with_method_to_proc }
# => 2.222132
bench(1000000) { with_send }
# => 0.686984
Upvotes: 0