我用Rails 4和rspec学习TDD。我为我的用户模型制作了一些测试用例来检查密码长度。到目前为止,我有两个测试,检查用户输入的密码是否太短,密码是否在6到10个字符之间。
到目前为止,密码太短了#34;测试通过:
it "validation says password too short if password is less than 6 characters" do
short_password = User.create(email: "tester@gmail.com", password: "12345")
expect(short_password).not_to be_valid
end
但是,在我拥有有效密码的测试中,它失败了:
it "validation allows passwords larger than 6 and less than 10" do
good_password = User.create(email: "tester2@gmail.com", password: "blahblah")
expect(good_password).to be_valid
end
我收到了这个错误:
Failure/Error: expect(good_password).to be_valid
expected #<User id: 1, email: "tester2@gmail.com",
created_at: "2014-06-21 02:43:42", updated_at: "2014-06-21 02:43:42",
password_digest: nil, password: nil, password_hash: "$2a$10$7u0xdDEcc6KJcAi32LBW7uzV9n7xYbfOhZWdcOnU5Cdm...",
password_salt: "$2a$10$7u0xdDEcc6KJcAi32LBW7u"> to be valid,
but got errors: Password can't be blank, Password is too short (minimum is 6 characters)
# ./spec/models/user_spec.rb:12:in `block (3 levels) in <top (required)>'
编辑:这是我的型号代码:
class User < ActiveRecord::Base
has_many :pets, dependent: :destroy
accepts_nested_attributes_for :pets, :allow_destroy => true
VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, format: { with: VALID_EMAIL_REGEX },
uniqueness: true
validates :password, presence: true, :length => 6..10, :confirmation => true
#callbacks
before_save :encrypt_password
after_save :clear_password
#method to authenticate the user and password
def self.authenticate(email, password)
user = find_by_email(email)
if user && user.password_hash == BCrypt::Engine.hash_secret(password, user.password_salt)
user
else
nil
end
end
#method to encrypt password
def encrypt_password
if password.present?
self.password_salt = BCrypt::Engine.generate_salt
self.password_hash = BCrypt::Engine.hash_secret(password, password_salt)
end
end
#clears password
def clear_password
self.password = nil
end
end
我在创建测试对象时对密码为零的原因感到困惑。
谢谢!
答案 0 :(得分:2)
最可能的问题是password
字段不是可分配的。这就是输出消息中password
为零的原因。
请改为尝试:
it "validation allows passwords larger than 6 and less than 10" do
good_password = User.create(email: "tester2@gmail.com")
good_password.password = "blahblah"
expect(good_password).to be_valid
end
请注意,您的第一次测试是偶然传递的 - 它与第二次测试存在相同的问题(密码未被分配)。这意味着当小于6个字符时,您实际上并未测试密码被拒绝。
有关详细信息,请参阅this article on mass assignment。
编辑:Leo Correa的评论可能暗示这可能不是你的情况。发布您的模型代码会有所帮助......答案 1 :(得分:1)
您对模型有一个密码提示要求,但是您有一个after_save
钩子,该钩子使密码无效并使记录处于无效状态。第一次测试通过是因为after_save
挂钩总是使您的记录处于无效状态。您需要重新考虑如何处理密码存储;解决此问题后,以下代码示例可帮助您提供一些测试方法:
# Set up a :user factory in spec/factories.rb; it should look something like:
FactoryBot.define do
factory :user do
sequence(:email) { |n| "tester+#{n}@gmail.com" }
password { SecureRandom.hex(6) }
end
end
# In your spec:
let(:user) { create :user, password: password }
context 'password' do
context 'length < 6' do
let(:password) { '12345' }
it { expect(user).not_to be_valid }
it { user.errors.message[:password]).to include('something') }
end
context 'length >= 6' do
context 'length < 10' do
let(:password) { 'blahblah' }
it { expect(user).to be_valid }
end
context 'length >= 10' do
let(:password) { 'blahblahblah' }
it { expect(user).not_to be_valid }
end
end
end
您也可以使用shoulda matchers:
it { should_not allow_value('12345').for(:password) }
it { should allow_value('12345blah').for(:password) }