在阅读Michael Hartl撰写的Ruby On Rails教程时,在作者编写集成测试以验证其注册页面的部分中,他使用了代码spinet。我得到了代码所做的但却无法理解“如何”部分,即无法理解执行顺序。
expect { click_button "Create my account" }.not_to change(User, :count)
有人可以解释上述方法和块链的语义以及它们如何组合在一起吗?
答案 0 :(得分:45)
您使用expect ... change
来验证特定方法调用是否更改 - 或不更改 - 其他一些值。在这种情况下:
expect { click_button "Create my account" }.not_to change(User, :count)
将导致rspec执行以下操作:
User.count
并记下返回的值。 (这可以指定为接收者和方法名称,例如示例中的(User, :count)
,或者作为任意代码块,如{ User.count }
。click_button "Create my account"
,这是一种模拟鼠标点击链接的Capybara方法。User.count
。其他使用方式expect ... change
:
expect { thing.destroy }.to change(Thing, :count).from(1).to(0)
expect { thing.tax = 5 }.to change { thing.total_price }.by(5)
expect { thing.save! }.to raise_error
expect { thing.symbolize_name }.to change { thing.name }.from(String).to(Symbol)
有些文档是here。
它是如何做到这一点有点神秘,而且根本不需要了解它如何使用它。对expect
的调用是使用rspec自己定制的DSL和" matchers系统定义rspec执行的结构。"加里·伯恩哈特(Gary Bernhardt)有一个相当整洁的screencast,他认为rspec的奥秘实际上是从像红宝石这样的动态语言中脱离出来的。它不是使用 rspec的好介绍,但如果您对它的工作原理感到好奇,您可能会觉得它很有趣。
<强>更新强>
在看到您对其他答案的评论后,我将添加一些关于操作顺序的内容。不直观的伎俩是它执行所有块的匹配器(在这种情况下为change
)。 expect
有一个lambda,not_to
是should_not
的别名,其作用是将lambda传递给匹配器。在这种情况下,匹配器是change
,它知道执行一次自己的参数,然后执行传递的lambda(来自expect
的那个),然后再次运行自己的参数以查看是否有变化。它很棘手,因为它看起来应该从左到右执行,但由于大多数部分只是传递代码块,所以它们可以并且将它们拖放到对匹配器最有意义的任何顺序中。 / p>
我不是rspec内部的专家,但这是我对基本理念的理解。
答案 1 :(得分:4)
以下是Ryan Bates Railscast on Request Specs and Capybara
的摘录require 'spec_helper'
describe "Tasks" do
describe "GET /tasks" do
it "displays tasks" do
Task.create!(:name => "paint fence")
visit tasks_path
page.should have_content("paint fence")
end
end
describe "POST /tasks" do
it "creates a task" do
visit tasks_path
fill_in "Name", :with => "mow lawn"
click_button "Add"
page.should have_content("Successfully added task.")
page.should have_content("mow lawn")
end
end
end
以下是the docs on RSPec Expectations
的摘录describe Counter, "#increment" do
it "should increment the count" do
expect{Counter.increment}.to change{Counter.count}.from(0).to(1)
end
# deliberate failure
it "should increment the count by 2" do
expect{Counter.increment}.to change{Counter.count}.by(2)
end
end
基本上,
expect { click_button "Create my account" }.not_to change(User, :count)
是RSpec的一部分:
expect {...}.not_to change(User, :count)
和部分Capybara
click_button "Create my account"
(此处为a link to the Capyabara DSL - 您可以搜索click_button
)
听起来你正在寻找他们两个的整体例子。这不是一个完美的例子,但它可能看起来像这样:
describe "Tasks" do
describe "GET /tasks" do
it "displays tasks" do
expect { click_button "Create my account" }.not_to change(User, :count)
end
end
end