如何使用 RSpec 在 Rails 中测试:包含验证
Posted
技术标签:
【中文标题】如何使用 RSpec 在 Rails 中测试:包含验证【英文标题】:How can I test :inclusion validation in Rails using RSpec 【发布时间】:2011-11-16 22:57:54 【问题描述】:我的 ActiveRecord 中有以下验证。
validates :active, :inclusion => :in => ['Y', 'N']
我正在使用以下内容来测试我的模型验证。
should_not allow_value('A').for(:active)
should allow_value('Y').for(:active)
should allow_value('N').for(:active)
有没有更干净、更彻底的测试方法?我目前正在使用 RSpec2 和 shoulda 匹配器。
编辑
环顾四周后,我才发现,这可能是一种“好的”测试方式,应该不为此提供任何东西,任何需要它的人都可以为它编写自己的自定义匹配器。(并且可能将其贡献回给该项目)。一些可能有趣的讨论链接:
指向上述内容的链接。 Link 1 , Link 2
should_ensure_value_in_range
这个接近可以使用的,但只接受范围而不是值列表。自定义匹配器可以基于此。
【问题讨论】:
【参考方案1】:使用 shoulda_matchers
在shoulda-matchers
的最新版本中(至少从 v2.7.0 开始),您可以:
expect(subject).to validate_inclusion_of(:active).in_array(%w[Y N])
这会测试验证中可接受值的数组是否与此规范完全匹配。
在早期版本中, >= v1.4 ,shoulda_matchers
支持这种语法:
it should ensure_inclusion_of(:active).in_array(%w[Y N])
【讨论】:
要检查它是否不允许其他值,您可以执行以下操作:it should_not allow_value('?').for(:active)
- 就像您说的,您无法检查所有可能的值,但除了检查所有允许的值之外,还可以这样做似乎是合理的覆盖范围。
@LarsLevie - 感谢您的评论。看起来他们将验证更改为检查disallows_value_outside_of_array?
。查看旧的github.com/thoughtbot/shoulda-matchers/blob/v1.2.0/lib/shoulda/… 与现在的github.com/thoughtbot/shoulda-matchers/blob/…
至少从shoulda-matchers v2.7.0
开始,此语法已被弃用。使用 RSpec 3.0 expect
语法的新首选语法是:expect(subject).to validate_inclusion_of(:active).in_array(%w[Y N])
匹配器的变化是不再是ensure_inclusion_of
,现在是validate_inclusion_of
仅供参考,当使用此布尔值运行测试套件时,我收到以下警告:Warning from shoulda-matchers: You are using "validate_inclusion_of" to assert that a boolean column allows boolean values and disallows non-boolean ones. Be aware that it is not possible to fully test this, as boolean columns will automatically convert non-boolean values to boolean ones. Hence, you should consider removing this test.
【参考方案2】:
如果您要测试的元素多于布尔 Y/N,那么您也可以尝试。
it "should allow valid values" do
%w(item1 item2 item3 item4).each do |v|
should allow_value(v).for(:field)
end
end
it should_not allow_value("other").for(:role)
您还可以将%w()
替换为您在模型中定义的常量,以便测试是否只允许使用常量值。
CONSTANT = %w[item1 item2 item3 item4]
validates :field, :inclusion => CONSTANT
然后是测试:
it "should allow valid values" do
Model::CONSTANT.each do |v|
should allow_value(v).for(:field)
end
end
【讨论】:
【参考方案3】:我发现了一个自定义的 shoulda 匹配器(在我正在从事的一个项目中),它试图接近测试类似这样的东西:
例子:
it should validate_inclusion_check_constraint_on :status, :allowed_values => %w(Open Resolved Closed)
it should validate_inclusion_check_constraint_on :age, :allowed_values => 0..100
匹配器试图确保存在一个 DB 约束,当它试图保存它时会爆炸。我将尝试给出这个想法的本质。比赛?实现类似于:
begin
@allowed_values.each do |value|
@subject.send("#@attribute=", value)
@subject.save(:validate => false)
end
rescue ::ActiveRecord::StatementInvalid => e
# Returns false if the exception message contains a string matching the error throw by SQL db
end
我想如果我们稍微改变一下上面的代码@subject.save
并让 Rails 验证崩溃,当异常字符串包含与真正的异常错误消息相匹配的内容时,我们可以返回 false。
我知道这远非完美回馈项目,但我想如果你真的想测试很多:inclusion
验证,作为自定义匹配器添加到你的项目中可能不是一个坏主意。
【讨论】:
我会在这里接受我自己的答案,因为我似乎找不到其他任何东西,但请随时批评上述解决方案如何失败,或者如果打扰这样做甚至是一个坏主意.以上是关于如何使用 RSpec 在 Rails 中测试:包含验证的主要内容,如果未能解决你的问题,请参考以下文章
使用 RSpec 测试 Rails 辅助方法时如何在参数哈希中设置值?
如何使用rails cucumber,rspec,capybara在视图(dhtml)中测试动态部分?
由于符号而不是 Rails 导致哈希失败的 RSpec 测试