如何测试使用rspec修改模型上的属性?

我想检查ActiveRecord对象上是否没有修改任何属性。 目前我这样做:

prev_attr = obj.attributes < – 这将给我一个带有attr名称和attr值的Hash

然后,稍后,我再次获取属性并比较两个哈希值。 还有另一种方式吗?

你应该能够使用平等匹配器 – 这不适合你吗?

 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 

确实有另一种方式。 你可以这样做:

 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 。

您可以使用ActiveRecord :: Dirty 。 它给你一个changed? 如果模型的任何属性实际更改,则模型上的方法是真实的,否则就是假的。 你也有_changed? 每个属性的方法,例如model.subject_changed? 如果与从数据库中读取对象相比,该属性发生了变化,这是真实的。

要比较属性值,可以使用model.subject_was ,它将是实例化对象时属性的原始值。 或者您可以使用model.changes ,它将返回一个带有属性名称作为键的哈希值,以及一个包含原始值和每个已更改属性的更改值的2元素数组。

不是一个完美的解决方案,但正如这里提到的,由于可维护性,我更喜欢它。

属性是缓存的,因为它们不会直接更改,所以如果要一次检查所有属性,则必须重新加载它们:

 it 'does not change the subject attributes' do expect { # Action }.to_not change { subject.reload.attributes } end 

如果可以,请避免重新加载,因为您正在强制向数据库发出另一个请求。