I have a simple Rails 4 application, and I'm trying to write some tests to check my user signup is working properly. I have a problem that when I'm running testcases with my hands, everything works ok, but when I write some integration tests and run them it skips my model's validations, so I'm getting database exceptions like
Minitest::UnexpectedError: ActiveRecord::RecordNotUnique: PG::UniqueViolation: ERROR: duplicate key value violates unique constraint "index_users_on_username"
test 'unique username violated' do
params = user_params # it is just a hash with User model attributes
User.new(params).save # saving user first time to violate unique after
params[:email] = 'Test@Email2'
assert_no_difference 'User.count' do
post users_path, user: params
end
assert_template 'users/new'
end
Example of my validation is below:
validates :username, :email, \
uniqueness: {uniqueness: true, message: 'Username&email must be unique'}, \
length: {maximum: 50, message: 'Length must be <= 50'}
It's not only this validation issue, but all the rest are not working in tests too.
If I'll validate my user object with something like, inside of a test, it will be false, as it should be.
User.new(params).valid?
My users#create action is below:
def create
@user = User.new user_params
if @user.save
flash[:success] = 'Welcome to the Sample App!'
redirect_to @user
else
render 'new'
end
end
my users#user_params method:
def user_params
user_group = UserGroup.find_by_name 'administrator'
if user_group.nil?
user_group = UserGroup.new name: 'administrator'
user_group.save
end
{username: 'TestUsername', password: 'TestPassword', \
password_confirmation: 'TestPassword', email: 'Test@Email', \
firstname: 'TestFirstname', lastname: 'TestLastname',user_group: user_group}
end
Rails validations don't really work that way. When you use:
validates :username, :email, uniqueness: true
You are adding a similar but separate validations for :username
and :email
. Consider this case:
user = User.new
user.valid?
assert(user.errors.has_key?(:username)) # pass
assert(user.errors.has_key?(:email)) # pass
When you print out the errors with user.errors.full_messages()
it will contain both Email has already been taken
and Username has already been taken
.
But if you override the message like so:
validates :username, :email, uniqueness: { message: 'Username&email must be unique' }
You will get Username&email must be unique
twice instead, which is not so great.
If for some reason you really need to have only one error you would add a custom validation method:
validate :uniqueness_of_username_and_email
def uniqueness_of_username_and_email
if User.where("username = ? OR email = ?", username, email).any?
errors.add(:email_username, 'Username&email must be unique')
end
end
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.