Ruby on rails RSpec看不到对ActiveRecord对象的更改,语法为'change(object,:message)`
我有三种型号:Ruby on rails RSpec看不到对ActiveRecord对象的更改,语法为'change(object,:message)`,ruby-on-rails,activerecord,integration-testing,rspec-rails,Ruby On Rails,Activerecord,Integration Testing,Rspec Rails,我有三种型号: 用户 公司 承诺 承诺是针对用户和公司的HABTM加入表(即,当用户加入公司时,它会创建一个新的承诺)。它还有几个额外的列/属性: admin(用户是否具有此公司的管理员权限?) 由\ u管理员确认\(公司管理员是否已确认此用户加入公司的请求?) 由成员确认(用户本人是否确认了加入公司的邀请?) 我还定义了一种方便的方法来快速确定承诺是否得到充分确认: class Commitment < ApplicationRecord def confirmed?
用户
公司
承诺
承诺
是针对用户
和公司
的HABTM加入表(即,当用户
加入公司
时,它会创建一个新的承诺
)。它还有几个额外的列/属性:
(用户是否具有此公司的管理员权限?)admin
(公司管理员是否已确认此用户加入公司的请求?)由\ u管理员确认\
由成员确认(用户本人是否确认了加入公司的邀请?)
class Commitment < ApplicationRecord
def confirmed?
confirmed_by_admin? && confirmed_by_member?
end
end
当RSpec测试变更时,carol.commonments.first
似乎没有被重新加载-我得到以下测试输出:
Failure/Error:
expect do
patch commitment_path(carol.commitments.first),
params: { commitment: { confirmed_by_member: true } }
end.to change(Commitment.find_by(user: carol, company: company), :confirmed?).from(false).to(true)
expected #confirmed? to have changed from false to true, but did not change
# ./spec/requests/commitments_spec.rb:69:in `block (3 levels) in <top (required)>'
故障/错误:
期望做
补丁承诺路径(carol.Commissions.first),
参数:{承诺:{成员确认}
结束。更改(承诺。查找人(用户:carol,公司:company),:已确认?)。从(假)。更改为(真)
预计#确认?从虚假变为真实,但没有改变
#./spec/requests/commissions_spec.rb:69:in `分块(3级)'
有什么好处?显然,我可以坚持大括号/块语法,但我想理解为什么一个有效,而另一个无效。当我自己检查并尝试一个新的rails项目复制您的场景,并且失败时,我相信失败的原因是
的“块”形式将运行两次(“在.change
块之前”和“在expect
块之后”),无论该块内部是什么:
.change{carol.commonments.first.confirmed?}
- 而
的“方法”形式对第一个参数运行一次:.change
,但对第二个参数运行两次carol.commissions.first
。但是,问题在于,此时规范文件中的:confirm?
与在carol.commissions.first
中实际更新的对象不共享相同的内存空间(该对象很可能被命名为commissions\u controller\update
)。虽然它们是相同的@commission
记录,但它们是单独的实例,并且当另一个发生更改时,另一个的属性值不会自动更改承诺
it 'sometest' do
commitment = FactoryGirl.create(:commitment, user: carol,
company: company,
confirmed_by_admin: true)
expect do
# this commitment object is exactly the same object passed in the `change` below
commitment.confirmed_by_member = true
end.to change(commitment, :confirmed?).from(false).to(true)
end
免责声明:这是未经验证的,但因为它太复杂,我无法将其作为注释(使用所有示例测试代码)来编写,所以我将其作为答案写在这里。如果有人知道得更好,请一定要告诉我。是的,我想就是这样。这似乎是最有可能的解释-
change
matcher不会在expect
块完成后重新加载传递给它的ActiveRecord对象。我将在GitHub上提交一个问题,只是为了再次检查,但我准备标记此问题已解决,除非其他人有更多可验证的见解。感谢反馈!很高兴知道你们也有同样的想法:)@RyanLue:这个问题很可能会被拒绝。RSpec不知道也不关心您是否向其传递activerecord对象。它可以是任何对象,但也许rspec rails应该这样做?
it 'sometest' do
commitment = FactoryGirl.create(:commitment, user: carol,
company: company,
confirmed_by_admin: true)
expect do
# this commitment object is exactly the same object passed in the `change` below
commitment.confirmed_by_member = true
end.to change(commitment, :confirmed?).from(false).to(true)
end