Rspec和Rails控制器期望

时间:2012-04-17 02:48:26

标签: ruby-on-rails rspec rspec2

所有

测试中存在一些问题,如下所示:

it "does something" do
  controller.should_receive(:some_method).once

  expect {
    post :create, some_params_hash, some_session_hash
  }.to change(Something, :count).by(1)
end

轨道上的控制器 - 粗略的例子:

class SomethingsController
  before_filter :some_method

  def create
    respond_with Something.create params[:something]
  end

  def some_method
    puts 'some_method'
  end
end

这一切都很好,并且运行得很好如果我删除了controller.should_receive期望。如果我把期望留在原地 - 测试失败了。

奇怪的是,它并没有失败,因为它实际上似乎满足了should_receive(:some_method)的期望 - 只是记录创建和后续的变更评估失败了。

所以 - 问题:

这是指定作为此测试的一部分调用的控制器的期望的正确方法吗?

感谢您的帮助!

1 个答案:

答案 0 :(得分:1)

一个常见的rspec错误是认为像should_receive设置的方法期望只是监视应用程序以确保发生某些事情。但实际上它会将自己插入到流中,并且完全替换方法。

所以你的控制器的some_method将被一个除了返回nil之外什么都不做的那个替换。并且返回nil的before过滤器将停止所有处理。你的行动从未被召唤过。

将您的期望改为:

controller.should_receive(:some_method).once.and_return true

另请注意,您的示例正在测试两件事 - 它确保您的操作调用some_method,并确保持久性Somethings的数量增加一。这没关系,但是如果你真的只打算检查后者,你可以使用存根而不是期望,这更紧凑:

controller.stub some_method: true

UPDATE:我应该在最新版本的Rails中添加它,忽略控制器过滤器的返回值。 (过滤器可以通过渲染内容来阻止动作执行。)但是,rspec的should_receive替换方法的原则仍然是正确的,并且通常适用。