如何使用Ruby中的Mocha模拟实际的Object#方法调用?

时间:2013-07-15 21:19:02

标签: ruby mocking mocha

直接与大脑交互并不容易,因此我使用了一些网关模式和一些依赖性反转。

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:未定义的方法`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*类。用mocha有没有更好的方法呢?

1 个答案:

答案 0 :(得分:0)

我认为您可以通过更改方法来解决问题。

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应该适用于您的案例,并适用于任何模拟框架。

Btw,我猜你的测试为什么不起作用,因为mocha不是stub 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