how to test rspec shoulda for custom validation in rails?
Asked Answered
A

2

9

I have a Private methods in my model like the following:

  validate :record_uniq

  private
  def record_uniq
    if record_already_exists?
      errors.add(:base, "already exists")
    end
  end

  def record_already_exists?
    question_id = measure.question_id
    self.class.joins(:measure).
    where(measures: {question_id: ques_id}).
    where(package_id: pack_id).
    exists?
  end

This methods is more like a uniqueness scope thing to prevent duplicate records. I want to know how to write test for validate :record_uniq by using shoulda or rspec?

Example of what i tried:

describe Foo do
  before do
    @bar = Foo.new(enr_rds_measure_id: 1, enr_rds_package_id: 2)
  end

  subject { @bar }

  it { should validate_uniqueness_of(:record_uniq) }
end
Antoniettaantonin answered 27/3, 2013 at 11:19 Comment(0)
A
12

Simple - build an object that fails the validation, validate it, and verify that the correct error message has been set.

For example (if you had a model named City):

it 'validates that city is unique' do
  city = City.new # add in stuff to make sure it will trip your validation
  city.valid?
  city.should have(1).error_on(:base) # or 
  city.errors(:base).should eq ["already exists"]
end
Adenectomy answered 27/3, 2013 at 11:25 Comment(6)
if any example would be more appreciated to understand clearly.Antoniettaantonin
I updated the question, and I used your answer but got an error of expected 1 error on :base, got 0Antoniettaantonin
Then your test is doing it's job. Now make it pass.Adenectomy
bit confusing... Will try that. ThanksAntoniettaantonin
If you want to change city.should have(1).error_on(:base) to using the newexpect syntax do it like this: expect(city).to have(1).error_on(:base)Haemostatic
I believe that the second proposed way to test the errors in this answer should be city.errors[:base]Glomerulonephritis
E
9

Here's what I would do using RSpec 3 syntax.

it 'validates that city is unique' do
  city = City.new('already taken name')
  expect(city).to be_invalid
  expect(city.errors[:base]).to include('already exists')
end
Ellsworthellwood answered 21/6, 2016 at 18:53 Comment(1)
can use expect(city.errors.full_messages).to/not_to include('full message')Atlanta

© 2022 - 2024 — McMap. All rights reserved.