Rspec::Matcher 'change' 接收方和消息与块的方法
Rspec::Matcher 'change' method with receiver and message vs. block
我正在尝试测试关联的删除。涉及的两个模型是User
和Cancellation
:
class Cancellation < Active Record::Base
belongs_to :taker, class_name: "User"
end
class User < ActiveRecord::Base
has_many :taken_cancellations, class_name: "Cancellation", foreign_key: :taker_id
end
在我的测试中,我得到了以下代码:
describe "Admin Calendar" do
subject { page }
let!(:user) { FactoryGirl.create(:user, name: "Taker User") }
let(:cancellation) { FactoryGirl.create(:cancellation, start_at: 2.days.from_now, taker: user) }
before do
sign_in admin
visit edit_admin_cancellation_path cancellation
end
#...
describe "Edit Page" do
it 'Making it available' do
expect { click_link "Make it available" }.to change(cancellation.reload, :taker).from(user).to nil
end
end
end
click_link 'Make it available
将在控制器中触发 user.taken_cancellations.delete @cancellation
。
测试失败并出现此错误:
taker should have been changed to nil, but is now #<User id: 1, name: "Taker User"...
来自 let
方法的指南:
https://relishapp.com/rspec/rspec-core/v/2-6/docs/helper-methods/let-and-let
The value will be cached
across multiple calls in the same example but not across examples.
对我来说,change
方法似乎是在操作之后创建一个新的 cancellation
,而不是查看记忆的方法。我没想到会有这种行为。
使用块时测试通过,如下所示:
expect { click_link "Make it available" }.to change { cancellation.reload.taker }.from(user).to nil
谁能解释一下我的看法是否正确?为什么会有这些不同的行为?
在第一种形式中,cancellation.reload
被求值一次,结果对象在 click_link
方法调用前后发送消息 taker
。换句话说,cancellation
对象在 click_link
被调用后 而不是 重新加载。
在第二种形式中,cancellation.reload.taker
在调用click_link
之前和之后被完整计算,因此reload
有机会在数据库更新后生效发生了。
但是请注意,根据您的配置,正在处理 click_link
结果的服务器可能在单独的线程中执行,因此在任何情况下,更新之间都存在竞争条件数据库和测试断言。
我正在尝试测试关联的删除。涉及的两个模型是User
和Cancellation
:
class Cancellation < Active Record::Base
belongs_to :taker, class_name: "User"
end
class User < ActiveRecord::Base
has_many :taken_cancellations, class_name: "Cancellation", foreign_key: :taker_id
end
在我的测试中,我得到了以下代码:
describe "Admin Calendar" do
subject { page }
let!(:user) { FactoryGirl.create(:user, name: "Taker User") }
let(:cancellation) { FactoryGirl.create(:cancellation, start_at: 2.days.from_now, taker: user) }
before do
sign_in admin
visit edit_admin_cancellation_path cancellation
end
#...
describe "Edit Page" do
it 'Making it available' do
expect { click_link "Make it available" }.to change(cancellation.reload, :taker).from(user).to nil
end
end
end
click_link 'Make it available
将在控制器中触发 user.taken_cancellations.delete @cancellation
。
测试失败并出现此错误:
taker should have been changed to nil, but is now #<User id: 1, name: "Taker User"...
来自 let
方法的指南:
https://relishapp.com/rspec/rspec-core/v/2-6/docs/helper-methods/let-and-let
The value will be cached across multiple calls in the same example but not across examples.
对我来说,change
方法似乎是在操作之后创建一个新的 cancellation
,而不是查看记忆的方法。我没想到会有这种行为。
使用块时测试通过,如下所示:
expect { click_link "Make it available" }.to change { cancellation.reload.taker }.from(user).to nil
谁能解释一下我的看法是否正确?为什么会有这些不同的行为?
在第一种形式中,cancellation.reload
被求值一次,结果对象在 click_link
方法调用前后发送消息 taker
。换句话说,cancellation
对象在 click_link
被调用后 而不是 重新加载。
在第二种形式中,cancellation.reload.taker
在调用click_link
之前和之后被完整计算,因此reload
有机会在数据库更新后生效发生了。
但是请注意,根据您的配置,正在处理 click_link
结果的服务器可能在单独的线程中执行,因此在任何情况下,更新之间都存在竞争条件数据库和测试断言。