Testing the validation of uniqueness of the field in Rails's model using rspec without helper gems

3.8k views Asked by At

I'm trying to write test to validate the uniqueness of the field in RoR's model.

I am working on Ruby on Rails apps which I use to practice my skills in TDD. I have used Internet as my resource so far. I'm writing testing on validation for model.I will not be using 'shoulda', 'FactoryGirl' (and etc) gems. I know using those gems will save me lots of coding but I will use those gems eventually. I want to learn how to write rspec test on it own without gems to help me understand how to write testing. I am doing good so far until 'uniqueness' testing.

How do I create test to validate the uniquenss of the 'email' field in 'User' model without using 'shoulda', 'FactoryGirl' (and etc) gems. I know using those gems will save lots of coding but I will use those gems eventually. I want to learn how to write rspec test on it own without gems to help me understand how to write testing.

Most 'answer' to this questions on Stackoverflow (and elsewhere on the Net) includes the use of those helper gems. But find no answer to this without gems.

Here is model, User.rb ```

class User < ApplicationRecord
  validate: :name, :email, presence: true
  validates :name, length: { minimum: 2 }
  validates :name, length: { maximum: 50 }
  # validates_format_of :email, with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i
  validates :email, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i, on: :create }
  validates :email, uniqueness: true
end

And here is `user_spec.rb`.

require 'rails_helper'

RSpec.describe User, type: :model do
  subject {
    described_class.new(name: 'John', email: '[email protected]')
  }

  describe 'Validation' do
    it 'is valid with valid attributes' do
      expect(subject).to be_valid
    end

    it 'is not valid without name' do
      subject.name = nil
      expect(subject).to_not be_valid
    end

    it 'is not valid without email' do
      subject.email = nil
      expect(subject).to_not be_valid
    end

    (...)

    it 'is invalid if the email is not unique' do
      expect(????????).to_not be_valid
    end

  end
end

```

how do I write to test for uniqueness. Should I use something else other than 'subject' to test against? Remember, I don't want a solution that use gems (Shoulda/FactoryGirl/etc) this time.

I've been at it for the last few days and no luck. Any solution? And where is the best tutorial on rspec on Ruby on Rails?

2

There are 2 answers

3
zwippie On BEST ANSWER

To test for uniqueness, first you have to create a user with same email as used in subject. Then, your subject would be invalid because of uniqueness validation on email.

Something like:

before { described_class.create!(name: 'foo', email: '[email protected]') }
it 'is invalid if the email is not unique' do
  expect(subject).to be_invalid
end
0
John Towery On

Ok I got it working. Ok, at the suggestion of @Jagdeep Singh, I wrote this test:

```

context 'when email is not unique' do
  before { described_class.create!(name: 'foo', email: '[email protected]') }
  it {expect(subject).to be_invalid}
end

context 'when email is unique' do
  before { described_class.create!(name: 'foo', email: '[email protected]') }
  it {expect(subject).to be_valid}
end

``` and it seems to pass the test. I added other test to test valid uniqueness. Thanks for the help.

I decided to rewrite whole test to make use of context to make it more clear and readable. Here is my rewrite:

# frozen_string_literal: true

require 'rails_helper'

RSpec.describe User, type: :model do
  subject {
    described_class.new(name: 'John', email: '[email protected]')
  }

  describe '.validation' do



    context 'when email is not unique' do
      before { described_class.create!(name: 'foo', email: '[email protected]') }
      it {expect(subject).to be_invalid}
    end

    context 'when email is  unique' do
      before { described_class.create!(name: 'foo', email: '[email protected]') }
      it {expect(subject).to be_valid}
    end

  end
end