我如何使用RSpec测试Rails中的包含验证

时间:2011-09-14 11:34:27

标签: ruby-on-rails-3 shoulda rspec-rails

我在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 matchers。

修改

经过一些环顾四周我发现,这可能是一种'好'的测试方式,如果没有为此提供任何东西,任何需要它的人都可以为它编写自己的自定义匹配器。(并且可能会将其贡献给它该项目)。可能有趣的讨论的一些链接:

  • 指示上述内容的链接。 Link 1Link 2

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

3 个答案:

答案 0 :(得分:61)

使用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]) }

答案 1 :(得分:24)

如果您要测试的元素多于布尔值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

答案 2 :(得分:1)

我找到了一个自定义应该匹配(在我正在进行的项目中)试图接近测试这样的东西:

示例:

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,那么作为自定义匹配器添加到项目中可能不是一个坏主意。验证