Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly use shoulda matchers with uniqueness validation?

I am trying rspec and shoulda matchers as my new testing framework and I'm a little confused as to how to get the should validate_uniqueness_of(:attribute) test to pass. Here is my simple model:

class Employee < ActiveRecord::Base
  validates :name, presence: true
  validates :title, presence: true
  validates :department, presence: true
  validates :avatar, presence: true 
  validates :email, presence: true, uniqueness: true
  validates :reports_to, presence: true
  mount_uploader :avatar, EmployeeAvatarUploader, on: :file_name
end

And here is the initial test:

RSpec.describe Employee, type: :model do
  it { should validate_presence_of(:name) }
  it { should validate_presence_of(:title) }
  it { should validate_presence_of(:department) }
  it { should validate_presence_of(:avatar) }
  it { should validate_presence_of(:email) }
  it { should validate_uniqueness_of(:email) } 
  it { should validate_presence_of(:reports_to) }
end

This fails with a description of the error pasted below:

`1) Employee should validate uniqueness of email
 Failure/Error: should validate_uniqueness_of(:email)

 Shoulda::Matchers::ActiveRecord::ValidateUniquenessOfMatcher::ExistingRecordInvalid:
   validate_uniqueness_of works by matching a new record against an
   existing record. If there is no existing record, it will create one
   using the record you provide.

   While doing this, the following error was raised:

     PG::NotNullViolation: ERROR:  null value in column "title" violates not-null constraint
     DETAIL:  Failing row contains (21, null, null, null, null, null, null, 2017-06-27 01:07:49.125445, 2017-06-27 01:07:49.125445, null, null).
     : INSERT INTO "employees" ("created_at", "updated_at") VALUES ($1, $2) RETURNING "id"

   The best way to fix this is to provide the matcher with a record where
   any required attributes are filled in with valid values beforehand.`

So my impression from the documentation was that my test should work as is. From the shoulda matcher documentation, I've tried this version of my test:

RSpec.describe Employee, type: :model do
  it { should validate_presence_of(:name) }
  it { should validate_presence_of(:title) }
  it { should validate_presence_of(:department) }
  it { should validate_presence_of(:avatar) }
  it { should validate_presence_of(:email) }
  it 'should validate uniqueness of email' do
    email1 = FactoryGirl.create(:account, email: '[email protected]')
    email2 = FactoryGirl.build(:account, email: '[email protected]' )
    should validate_uniqueness_of(:email)
  end
  it { should validate_presence_of(:reports_to) }
end

This didn't seem to work either. Then I tried a variation of this test found by clicking Rspec validates_uniqueness_ofthis link

But still no luck. Could someone please direct me to the proper way of making this validation work?

like image 533
Dan Rubio Avatar asked Jun 27 '17 01:06

Dan Rubio


1 Answers

You should be able to call it this way:

describe "validations" do
  subject { Employee.new(title: "Here is the content") }
  it { should validate_uniqueness_of(:email) }
end

Or with FactoryGirl:

describe "validations" do
  subject { FactoryGirl.build(:employee) }
  it { should validate_uniqueness_of(:email) }
end

Your employees table has a database level constraint requiring title, so you need to create a valid employee object first.

It looks as though in your second example you're building a account instead of employee.

See docs here: docs

like image 159
treiff Avatar answered Sep 25 '22 23:09

treiff