我想检查ActiveRecord对象上是否没有修改任何属性。目前我正在这样做:
prev_attr = obj.attributes
< - 这会给我一个带有attr名称和attr值的哈希
然后,我再次抓住属性并比较两个哈希值。还有另一种方式吗?
答案 0 :(得分:8)
确实有另一种方式。你可以这样做:
it "should not change sth" do
expect {
# some action
}.to_not change{subject.attribute}
end
请参阅https://www.relishapp.com/rspec/rspec-expectations/v/2-0/docs/matchers/expect-change。
答案 1 :(得分:3)
您可以使用ActiveRecord::Dirty。它为您的模型提供了changed?
方法,如果模型的任何属性实际更改,则该方法是真实的,如果不是,则为假。您还可以为每个属性设置_changed?
种方法,例如model.subject_changed?
如果与从数据库中读取对象相比,该属性发生了变化,这是真实的。
要比较属性值,可以使用model.subject_was
,它将是实例化对象时属性的原始值。或者您可以使用model.changes
返回一个带有属性名称作为键的哈希值和一个包含原始值和每个已更改属性的更改值的2元素数组。
答案 2 :(得分:2)
你应该能够使用equality matchers - 这对你不起作用吗?
a = { :test => "a" }
b = { :test => "b" }
$ a == b
=> false
b = { :test => "a" }
$ a == b
=> true
或者使用你的例子:
original_attributes = obj.attributes
# do something that should *not* manipulate obj
new_attributes = obj.attributes
new_attributes.should eql original_attributes
答案 3 :(得分:1)
这不是一个完美的解决方案,但正如此处所述,由于可维护性,我更喜欢它。
属性已缓存,由于它们没有直接更改,因此如果要一次检查所有属性,则必须重新加载它们:
it 'does not change the subject attributes' do
expect {
# Action
}.to_not change { subject.reload.attributes }
end
如果可能的话,请避免重新加载,因为您是在向数据库强制另一个请求。