Search code examples
ruby-on-railsrubyrspecrspec-rails

Testing Rails model uniqueness with duplicate entry


I have a restriction on my Rails DB to force unique usernames, and I create a user at the start of each of my model tests. I'm trying to create a second user with the same username as the first and I expect this to not be valid, but it is returning as valid.

I've tried tweaking the code to use the new, save, and create methods when generating new users but with no success.

Registration Model:

class Registration < ApplicationRecord
  @username_length = (3..20)
  @password_requirements = /\A
    (?=.{8,}) # Password must be at least 8 characters
    (?=.*\d) # Password must contain at least one number
    (?=.*[a-z]) # Password must contain at least one lowercase letter
    (?=.*[A-Z]) # Password must contain at least one capital letter
    # Password must have special character
    (?=.*[['!', '@', '#', '$', '%', '^', '&']])
  /x

  validates :username, length: @username_length, uniqueness: true
  validates :password, format: @password_requirements
  validates :email, uniqueness: true
  has_secure_password
  has_secure_token :auth_token

  def invalidate_token
    self.update_columns(auth_token: nil)
  end

  def self.validate_login(username, password)
    user = Registration.find_by(username: username)
    if user && user.authenticate(password)
      user
    end
  end
end

Registration Tests:

require 'rails_helper'

RSpec.describe Registration, type: :model do
  before do
    @user = Registration.new(
      username: '1234',
      password: 'abcdeF7#',
      email: '[email protected]',
      name: 'One'
    )
  end
  it 'should not be valid if the username is already taken' do
    @user.save!(username: '1234')
    expect(@user).not_to be_valid
  end
end

I would expect this test to pass due to it being a duplicate username.


Solution

  • As fabio said, you dont have second Registration object to check uniquness. You just checked your saved @user is valid or not which is always valid and saved in DB. To check your uniqueness validation you can do something like this -

    RSpec.describe Registration, type: :model do
      before do
        @user = Registration.create(
          username: '1234',
          password: 'abcdeF7#',
          email: '[email protected]',
          name: 'One'
        )
        @invalid_user = @user.dup
        @invalid_user.email = "[email protected]"
      end
      it 'should not be valid if the username is already taken' do
        expect(@invalid_user.valid?).should be_falsey
      end
    end