您的功能请求是否与问题有关?
检查属性是否已更改的最常见方法似乎是检查该属性值是否等于您的预期。
这对我来说很不清楚,因为有时您不确定该属性的初始值是什么,并且您不想为了确认而开始检查工厂。
描述您想要的解决方案
如果我们有一个匹配器来检查属性名称是否更改为某事,那就太好了。
例如expect { update_user }.to change(user.reload, :name).to 'Kaka Ruto'
和expect { update_user }.not_to change(user.reload, :name).to 'Kaka Ruto'
描述您考虑过的替代方案
我必须检查该属性的值是否等于我的预期。 例如expect(user.reload.name).to eq 'Kaka Ruto'
附加上下文
我尝试使用现有的更改匹配器,但出现意外行为。
对于这个测试, expect { update_user }.to change(user.reload, :name).to 'Kaka Ruto'
,我得到了一个失败的规范,描述expected 'User#name' to have changed to "Kaka Ruto", but did not change
。 但是,它是否定的变体通行证! 这expect { update_user }.not_to change(user.reload, :name)
实际上通过
此代码的问题是reload
在更改之前发送。
所以基本上是这样的:
expect { update_user }.to change(user.reload, :name).to 'Kaka Ruto'
扩展为:
object = user.reload
old_value = object.send(:name)
update_user
new_value = object.send(:name)
expect(new_value).not_to eq(old_value) # i.e. "change"
expect(new_value).to eq('Kaka Ruto')
这里有两个问题。 一种是reload
在更改之前执行。 您可能希望它在更改后重新加载。
另一个是您必须重新加载,代码中的某些内容而不是使用模型是通过 id 找到它并从头开始重新实例化它,因此测试中实例化的与测试代码中的不同步强迫你重新加载。
我建议你使用:
expect { update_user }.to change { user.reload.name }.to 'Kaka Ruto'
这样做的缺点是reload
在更改之前和之后执行了两次。
我见过类似change_reloaded(model, attribute_name)
匹配器的东西,它在更改之前保存值以进行比较,然后在更改之后重新加载并进行比较。
但是, update_user
从数据库加载模型的问题仍然存在。
如果您觉得rspec-rails
不完整或有一些缺陷,请随时重新打开。
谢谢@pirj ! 这确实有帮助。
随时欢迎您!
为避免双重重新加载,您还可以执行以下操作:
expect { update_user; user.reload }.to change { user.name }.to 'Kaka Ruto'
@JonRowe 很漂亮!
最有用的评论
为避免双重重新加载,您还可以执行以下操作: