【问题标题】:How to mock an actual Object#method call using Mocha in Ruby?如何在 Ruby 中使用 Mocha 模拟实际的 Object#method 调用?
【发布时间】:2013-07-15 21:19:01
【问题描述】:

直接与大脑交互并不容易,所以我使用了一个小网关模式和一些依赖倒置。

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* 类。有没有更好的方法来用 mocha 做到这一点?

【问题讨论】:

  • 你试过@brain.expects(:method).with(:multiply_by_100)...吗?

标签: ruby mocking ruby-mocha


【解决方案1】:

我认为你可以通过改变你的方法来解决你的问题。

来自

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

【讨论】:

  • 我使用&method 的原因是为了编写更少的代码。如果我要扩展它,我可能会使用numbers.map { |n| @brain.multiply_by_100 n } 而不是method.to_procsend... 我的意思是我不想改变我的Number 类的编写方式。我觉得 Mocha 应该允许我在我的实现中使用任何模式。
  • 另外,请在提供基准测试时提供您的 Ruby 版本。
  • 并不是说这对我有帮助,但我认为这是一个更相关的基准:gist.github.com/naomik/6012203
  • 是的,我猜你的基准测试更好。如果您认为 mocha 应该具有该功能,您应该提出问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-25
  • 2022-11-01
  • 1970-01-01
  • 2018-04-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多