ruby-on-railsvalidationrspecmongoidvalidates-uniqueness-of

rspec mongoid validation of uniqueness


I would like to test the uniquness of User model.

My User model class looks like:

class User
  include Mongoid::Document
  field :email, type: String
  embeds_one :details

  validates :email,
      presence: true,
      uniqueness: true,
      format: {
        with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z0-9]{2,})\Z/i,
        on: :create
      },
      length: { in: 6..50 }

end

My rspec test which belongs to the model looks like:

...
before(:each) do
  FactoryGirl.create(:user, email: taken_mail)
end

it "with an already used email" do
  expect(FactoryGirl.create(:user, email: taken_mail)).to_not be_valid
end

After I executed bundle exec rspec it always raises the next error instead of passed with success:

Failure/Error: expect(FactoryGirl.create(:user, email: taken_mail)).to_not be_valid
     Mongoid::Errors::Validations:

       Problem:
         Validation of User failed.
       Summary:
         The following errors were found: Email is already taken
       Resolution:
         Try persisting the document with valid data or remove the validations.

If I use this it passes with success:

it { should validate_uniqueness_of(:email) }

I would like to use expect(...). Can anybody help me out?


Solution

  • The issue is you are trying to persist an invalid object into the database, which throws an exception and breaks the test (because email is not unique), before even the test is done using the expect method.

    The correct way is to use build here instead of create, which doesn't persist the object in the database, by building the record only in memory and allowing your test to do its job. Therefore to fix it:

    expect(FactoryGirl.build(:user, email: taken_mail)).to_not be_valid
    

    Also note that is better to use build rather than create if you don't need to actually save the record in the database, since it's a cheaper operation and you will get the same outcome, unless for some reason your record must be saved to the database for your tests to work in a way you want them, such as saving the first record in in your example.