Daniel
Daniel

Reputation: 165

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.

Upvotes: 1

Views: 1060

Answers (2)

SujoyD
SujoyD

Reputation: 159

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

Upvotes: 3

Mosaaleb
Mosaaleb

Reputation: 1089

@user.save! will raise an error even before reaching the expect as mentioned in comments by Fabio

Also, if it is important to you to test db level constraint you can do:

expect { @user.save validate: false }.to raise_error(ActiveRecord::RecordNotUnique)

Upvotes: 1

Related Questions