如何检查对rspec中构造函数调用的方法的调用?

时间:2013-08-05 18:02:32

标签: ruby rspec

如果我有一个构造函数调用另一个函数的类,我该如何检查它是否被调用了正确的次数?

class MyClass
  def initialize(count)
    count.times{self.do_something}
  end

  def do_something
    # whatever
  end

end

我想说点什么

n = 4
MyClass.new(n).should_receive(:do_something).exactly(n).times
n = 2
MyClass.new(n).should_receive(:do_something).exactly(n).times

但是失败是因为在do_receive附加到do_someive之前调用了do_something(至少我认为这就是原因)。

expected: 4 times with any arguments
received: 0 times with any arguments

或者从构造函数中调用这样的东西是不对的,我应该重构一下?

此外,这个问题与此问题非常相似:

rspec: How to stub an instance method called by constructor?

但是我希望在过去的5年里,答案比设置存根new电话的手动实施要好。

4 个答案:

答案 0 :(得分:7)

执行此操作的新语法如下:

allow_any_instance_of(ExampleClass).to receive(:example_method).and_return("Example")
expect_any_instance_of(ExampleClass).to receive(:example_method).and_return("Example")

See the docs

答案 1 :(得分:2)

期望被放置在预期会满足它们的代码之前。

MyClass.any_instance.should_receive(:do_something).exactly(1).time
MyClass.new

这应该有效。

答案 2 :(得分:2)

另一个答案是使用rspec间谍。这里的问题是你必须在事后为你想要的方法创建一个模拟。事实证明这并不难,但你仍然需要列举它们。 and_call_original是使实现不变的神奇之处。

MyClass.any_instance.stub(:method_name).and_call_original

然后你可以说:

MyClass.new(4).should have_received(:method_name).exactly(4).times

但我仍然希望找到一种不需要你枚举方法的方法。

答案 3 :(得分:0)

这是我提出的最好的,但我不喜欢它:

在Class中创建一个新方法,该方法在已分配但尚未初始化的对象上运行块。我把它放在我的spec文件的before块中,但是它可能是一个更好的地方:

class Class
  def rspec_new(*params, &block)
    o = allocate
    yield(o) if block
    o.__send__(:initialize, *params)
    return o
  end
end

然后这样称呼:

MyClass.rspec_new(n){|obj| obj.should_receive(:do_something).exactly(n).times}

它似乎工作,但你不能传递一个块到你的构造函数。至少不是你通常的做法。这就是我没有覆盖常规new方法的原因。