在阅读 Michael Hartl 的 Ruby On Rails 教程时,在作者编写集成测试以验证他的注册页面的部分中,他使用了下面的代码尖峰。我得到了代码的作用,但无法理解“如何”部分,即无法理解执行顺序。
expect { click_button "Create my account" }.not_to change(User, :count)
有人可以解释上述方法和块链的语义以及它们如何组合在一起吗?
在阅读 Michael Hartl 的 Ruby On Rails 教程时,在作者编写集成测试以验证他的注册页面的部分中,他使用了下面的代码尖峰。我得到了代码的作用,但无法理解“如何”部分,即无法理解执行顺序。
expect { click_button "Create my account" }.not_to change(User, :count)
有人可以解释上述方法和块链的语义以及它们如何组合在一起吗?
您将使用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)
一些文档在这里。
它是如何做到的有点神秘,而且完全没有必要了解它是如何工作的以便使用它。调用expect
是定义一个结构供 rspec 执行,使用 rspec 自己的自定义 DSL 和“匹配器”系统。Gary Bernhardt 有一个相当简洁的截屏视频,他认为 rspec 的奥秘实际上是从像 ruby 这样的动态语言中自然而然地消失的。这不是一个很好的使用rspec 的介绍,但如果你对它的工作原理感到好奇,你可能会觉得它很有趣。
更新
在看到您对另一个答案的评论后,我将添加一些关于操作顺序的信息。不直观的技巧是执行所有块的是匹配器(change
在这种情况下)。expect
有一个 lambda,not_to
是一个别名,should_not
其工作是将 lambda 传递给匹配器。在这种情况下,匹配器change
知道执行一次它自己的参数,然后执行它传递的 lambda(来自 的那个expect
),然后再次运行它自己的参数以查看是否有变化。这很棘手,因为该行看起来应该从左到右执行,但由于大多数片段只是传递代码块,它们可以并且确实将它们打乱成对匹配器最有意义的任何顺序。
我不是 rspec 内部的专家,但这是我对基本思想的理解。
这是Ryan Bates Railscast 关于 Request Specs 和 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
这是RSPec 期望文档的摘录
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)
和部分水豚
click_button "Create my account"
(这里是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