How can I test :inclusion validation in Rails using RSpec

前端 未结 3 1018
终归单人心
终归单人心 2021-01-31 15:14

I have the following validation in my ActiveRecord.

validates :active, :inclusion => {:in => [\'Y\', \'N\']}

I am using the following to

相关标签:
3条回答
  • 2021-01-31 15:47

    I found one custom shoulda matcher (in one of the projects I was working on) which attempts to coming close to test something like this:

    Examples:

    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 }
    

    The matcher tries to ensure that there is a DB constraint which blows up when it tries to save it.I will attempt to give the essence of the idea. The matches? implementation does something like:

      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
    

    I guess if we slightly change the above to say @subject.save and let Rails validation blow up, we can return false when the exception string contains something which close matches the real exception error message.

    I know this is far from perfect to contributed back to the project, but I guess might not be a bad idea to add into your project as a custom matcher if you really want to test a lot of the :inclusion validation.

    0 讨论(0)
  • 2021-01-31 15:54

    If you have more elements to test than a boolean Y/N then you could also try.

    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) }
    

    You can also replace the %w() with a constant you have defined in your model so that it tests that only the constant values are allowed.

    CONSTANT = %w[item1 item2 item3 item4]
    validates :field, :inclusion => CONSTANT
    

    Then the test:

    it "should allow valid values" do
      Model::CONSTANT.each do |v|
        should allow_value(v).for(:field)
      end
    end
    
    0 讨论(0)
  • 2021-01-31 15:57

    Use shoulda_matchers

    In recent versions of shoulda-matchers (at least as of v2.7.0), you can do:

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

    This tests that the array of acceptable values in the validation exactly matches this spec.

    In earlier versions, >= v1.4 , shoulda_matchers supports this syntax:

    it {should ensure_inclusion_of(:active).in_array(%w[Y N]) }
    
    0 讨论(0)
提交回复
热议问题