41

我的 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 匹配器。

编辑

经过一番环顾后,我才发现,这可能是一种“好的”测试方式,应该不为此提供任何东西,任何需要它的人都可以为它编写自己的自定义匹配器。(并且可能将其贡献回项目) . 一些可能有趣的讨论链接:

  • 指向上述内容的链接。链接 1 ,链接 2

  • should_ensure_value_in_range这个接近可以使用的,但只接受范围而不是值列表。自定义匹配器可以基于此。

4

3 回答 3

72

使用 shoulda_matchers

在最新版本shoulda-matchers(至少从 v2.7.0 开始)中,您可以执行以下操作:

expect(subject).to validate_inclusion_of(:active).in_array(%w[Y N])

这将测试验证中可接受值的数组是否与此规范完全匹配。

在早期版本中, >= v1.4shoulda_matchers支持以下语法:

it {should ensure_inclusion_of(:active).in_array(%w[Y N]) }
于 2012-08-06T15:58:40.010 回答
25

如果您有比布尔 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
于 2011-10-18T03:59:49.487 回答
1

我发现了一个自定义的 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验证,将其作为自定义匹配器添加到你的项目中可能不是一个坏主意。

于 2011-09-22T03:04:37.370 回答