Rspec嘲讽,可以'期待'还会将方法作为副作用吗?

tom*_*ave 10 ruby rspec ruby-on-rails 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
Run Code Online (Sandbox Code Playgroud)

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

现在,在我看来,使用expect内部before块是错误的.让我们暂时忘掉这一点.

通常上面的测试是绿色的.
但是,如果我删除expect行,则测试失败.在这种情况下似乎是在expect视图上存根方法.事实上,替换expectallow似乎有完全一样的效果.

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

然而,在这里,expect设定一个期望,同时,view用固定的返回值来固定方法.由于视图模板调用该方法,因此测试通过.

关于那个意外的"存根"副作用expect,我在rspec-mocks自述文件中发现了这个:

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

person = double("person")
expect(Person).to receive(:find) { person }
Run Code Online (Sandbox Code Playgroud)

RSpec 用它自己的类似测试的方法取代了我们使用它进行存根或模拟的方法.在示例的最后,RSpec验证任何消息期望,然后恢复原始方法.

有没有人对这种方法的具体使用有任何经验?

Uri*_*ssi 22

那就是expect().to receive()这样的!这是(不那么)新期待语法rspec,它取代了should_receiveAPI

expect(view).to receive(:job_post).at_least(:once).and_return(job_post)
Run Code Online (Sandbox Code Playgroud)

相当于

view.should_receive(:job_post).at_least(:once).and_return(job_post)
Run Code Online (Sandbox Code Playgroud)

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

view.should_receive(:job_post).at_least(:once).and_call_original
Run Code Online (Sandbox Code Playgroud)

关于其他一些问题:

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

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

事实上,替换expectallow似乎有完全一样的效果.

allow语法替换stub旧rspec的语法方法,所以是的,它具有相同的效果,但不同的是,它不会失败的测试,如果存根方法叫.


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

应该在测试中包含的内容正确调用那些HTTP调用,IO读取和外部服务.为此,您需要设置消息期望 - 您希望测试的方法调用某个方法(其实际功能超出了测试范围).所以你希望服务接收一个方法调用,使用正确的参数,一次或多次(你可以明确地指望它应被调用多少次),并且,作为交换它实际被调用,你存根它,并根据测试时,设置其返回值.

资料来源: