[英]How to mock an actual Object#method call using Mocha in Ruby?
直接與大腦交互並不容易,所以我使用了一個帶有一些依賴倒置的小網關模式。
NumberCruncher
是我的Brain
類的包裝器。
class NumberCruncher
def initialize brain = Brain.new
@brain = brain
end
def times_one_hundred *numbers
numbers.map &@brain.method(:multiply_by_100)
end
end
我在測試時遇到錯誤:
NameError: 未定義類 `Mocha::Mock' 的方法 `multiply_by_100'
這是測試
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
我假設這是因為&@brain.method(:multiply_by_100)
調用和 mocha 通過使用method_missing
或其他東西來工作。 唯一的解決方案似乎是更改設置
class NumberCruncherTest
class FakeBrain
def multiply_by_100; end
end
def setup
@brain = FakeBrain.new
@cruncher = NumberCruncher.new @brain
end
# ...
end
但是,我認為這種解決方案很糟糕。 它很快變得混亂,並且在我的測試中放置了大量的Fake*
類。 有沒有更好的方法用摩卡來做到這一點?
我認為你可以通過改變你的方法來解決你的問題。
從
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) }
到
numbers.map {|number| @brain.send(:multiply_by_100, number) }
這實際上更好,因為您的代碼存在一些問題。 將對象方法轉換為 proc(正如您正在做的那樣),有點將對象的狀態凍結到 proc 中,因此對實例變量的任何更改都不會生效,並且可能會更慢。 send
應該可以在您的情況下正常工作,並且可以與任何模擬框架一起使用。
順便說一句,我猜測為什么您的測試不起作用是因為 mocha 不存根 proc 方法,而且是好的,因為如果您將方法轉換為 proc,您將不再測試方法調用,而是測試 proc 調用。
因為每個人都喜歡基准測試:
@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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.