Rspec嘲笑,可以期待'还有一个方法作为副作用?

时间:2014-03-26 19:56:18

标签: ruby-on-rails ruby rspec rspec-mocks

我试图理解继承应用中的测试,我需要一些帮助。

有很多像这样的规范组(视图规范):

let(:job_post) { FactoryGirl.create(:job_post) }

# ...

before do
  expect(view).to receive(:job_post).at_least(:once).and_return(job_post)
end

it "should render without error" do
  render
end

... job_post是控制器上定义的辅助方法。 (是的,他们可以使用@instance变量,而我正在重构它)。

现在,我认为在expect块中使用before是错误的。让我们暂时忘掉这一点。

通常上面的测试是绿色的 但是,如果我删除 expect行,则测试失败。看来在这种情况下expect正在查看视图上的方法。事实上,将expect替换为allow似乎具有完全相同的效果。

我认为正在发生的事情通常是 - 当与服务器一起运行时 - 视图将调用job_posts并且消息将登陆上的辅助方法控制器,这是预期的行为。

但是,expect设置了一个期望值,同时在view上使用固定的返回值来存根方法。由于视图模板调用该方法,因此测试通过。

关于那个意外的"存根" expect的副作用,我在rspec-mocks readme

中发现了这一点
  

(...)我们还可以设置消息期望,以便在未调用find时示例失败:

person = double("person")
expect(Person).to receive(:find) { person }
     

RSpec 用我们自己的类似测试方法取代了我们正在抄写或嘲笑的方法。在示例的最后,RSpec验证任何消息期望,然后恢复原始方法。

有没有人对该方法的这种特定用途有任何经验?

3 个答案:

答案 0 :(得分:21)

嗯,这就是expect().to receive()的作用!这是rspec的{​​{1}}新expectation syntax,取代了should_receive API

expect(view).to receive(:job_post).at_least(:once).and_return(job_post)

相当于

view.should_receive(:job_post).at_least(:once).and_return(job_post)

此API将期望设置为返回值。这是默认行为。要实际调用原始方法,您需要明确说出:

view.should_receive(:job_post).at_least(:once).and_call_original

关于其他一些问题:

  

(是的,他们本可以使用@instance变量,而我正在重构它)。

let API在rspec测试中非常普遍,并且在许多情况下可能比@instance变量更好(例如 - 它是懒惰的,所以它只在需要时运行,并且它被记忆,因此它运行最多一次)。

  

事实上,将expect替换为allow似乎具有完全相同的效果。

allow语法替换了旧的rspec语法中的stub方法,所以是的,它具有相同的效果,但不同的是,如果存根方法不会使测试失败是被调用。


正如OP所要求的那样 - 关于should_receive的一些解释 - 单元测试预计将单独运行 。这意味着不应该测试不是直接部分测试的所有内容。这意味着HTTP调用,IO读取,外部服务,其他模块等不是测试的一部分,并且出于 测试的目的,您应该假设他们工作正常。

在测试中应包含的内容是正确调用那些HTTP调用,IO读取和外部服务 。为此,您设置消息期望 - 您期望测试方法调用某种方法(其实际功能超出了考试)。因此,期望服务接收方法调用,使用正确的参数,一次或多次(您可以明确地预期应该调用多少次),以及以换取它实际被调用,你存根它,并根据测试,设置它的返回值。

<强>来源:

答案 1 :(得分:1)

如果您不想将存根视为副作用,则可以随时调用原始照片。

https://relishapp.com/rspec/rspec-mocks/v/2-14/docs/message-expectations/calling-the-original-method

例如我曾经想要监视一个方法,但也调用函数,否则它有其他方面的影响。这确实有帮助。

https://relishapp.com/rspec/rspec-mocks/v/2-14/docs/message-expectations/calling-the-original-method

答案 2 :(得分:0)

Rspec是一个元宝石,它依赖于rspec核心,rspec期望和rspec-mocks宝石。 Rspec-mocks是rspec的测试双重框架,支持对生成的测试双精度和真实对象的方法存根,假货和消息期望。

allow().to receive

是使用&#39; Method Stubs&#39;但是

expect().to receive

是使用&#39;消息期望&#39;

您可以参考Doc了解更多详情