【问题标题】:Rspec be_valid fails on a valid testRspec be_valid 在有效测试中失败
【发布时间】:2014-06-21 02:52:37
【问题描述】:

我正在学习使用 Rails 4 和 rspec 的 TDD。我为我的用户模型制作了一些测试用例来检查密码长度。到目前为止,我有两个测试来检查用户输入的密码是否太短,一个是密码在 6 到 10 个字符之间。

到目前为止,“密码太短”测试通过了:

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

我对为什么创建测试对象时密码为 nil 感到困惑。

谢谢!

【问题讨论】:

  • 您的模型必须有一些影响密码计算方式的回调。这表明 password_hashpassword_salt 正在填充。你能显示你的型号代码吗?

标签: ruby-on-rails rspec


【解决方案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) }

【讨论】:

    【解决方案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 个字符 atm 时是否被拒绝。

    更多详情请见this article on mass assignment

    编辑:Leo Correa 的评论可能暗示您可能并非如此。发布您的模型代码会有所帮助...

    【讨论】:

    • 5 年过去了...批量分配已移至 Rails 4 中的控制器层。没有任何东西(默认情况下)应该阻止分配模型上的任何字段。
    猜你喜欢
    • 2023-03-03
    • 2018-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多