我正在开发一个RoR 4应用程序,遵循Michael Hartl的教程。
实施用户身份验证测试时,一切都很顺利。我有一些比书中更多的必填字段,这是模型:
class User < ActiveRecord::Base
before_save { self.email = email.downcase }
VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
validates :playground_id, presence: true
validates :default_playground_id, presence: true
validates :active_from, presence: true
validates :active_to, presence: true
validates :last_name, presence: true, length: { maximum: 100 }
validates :login, presence: true, uniqueness: true, length: { maximum: 30 }
validates :email, presence: true, uniqueness: true, length: { maximum: 100 }, format: { with: VALID_EMAIL_REGEX }
validates :directory_id, length: { maximum: 100 }
validates :first_name, length: { maximum: 100 }
validates :password_digest, length: { maximum: 100 }
validates :remember_token, length: { maximum: 100 }
validates :created_by, length: { maximum: 30 }
validates :updated_by, length: { maximum: 30 }
has_secure_password
end
以下是与身份验证过程相关的测试:
###USER6 to test that password is correctly managed
describe "when password is not present" do
before do
@user = User.new(playground_id: 0, default_playground_id: 0, last_name: "Other User", login: "OTHER_USR",
email: "other@example.com", active_from: "2013-01-01", active_to: "2113-01-01", is_admin: 1.zero?,
password: " ", password_confirmation: " ")
end
it { should_not be_valid }
end
describe "when password doesn't match confirmation" do
before { @user.password_confirmation = "mismatch" }
it { should_not be_valid }
end
describe "with a password that's too short" do
before { @user.password = @user.password_confirmation = "a" * 5 }
it { should be_invalid }
end
describe "return value of authenticate method" do
before { @user.save }
let(:found_user) { User.find_by(email: @user.email) }
describe "with valid password" do
it { should eq found_user.authenticate(@user.password) }
end
describe "with invalid password" do
let(:user_for_invalid_password) { found_user.authenticate("invalid") }
it { should_not eq user_for_invalid_password }
specify { expect(user_for_invalid_password).to be_false }
end
end
### end
是的,它运作正常!以下是运行测试的结果:
Failures:
1) User model validation: with a password that's too short should be invalid
Failure/Error: it { should be_invalid }
expected invalid? to return true, got false
# ./spec/models/user_spec.rb:171:in `block (3 levels) in <top (required)>'
Finished in 0.28647 seconds
37 examples, 1 failure
Failed examples:
rspec ./spec/models/user_spec.rb:171 # User model validation: with a password that's too short should be invalid
Randomized with seed 18843
现在,如果我在用户模型中添加密码长度验证:
...
validates :created_by, length: { maximum: 30 }
validates :updated_by, length: { maximum: 30 }
has_secure_password
validates :password, length: { minimum: 6 }
end
运行测试会返回有关未定义的身份验证方法的错误,甚至会进行与身份验证无关的制动测试:
...
5) User model validation: return value of authenticate method with invalid password
Failure/Error: let(:user_for_invalid_password) { found_user.authenticate("invalid") }
NoMethodError:
undefined method `authenticate' for nil:NilClass
# ./spec/models/user_spec.rb:183:in `block (4 levels) in <top (required)>'
# ./spec/models/user_spec.rb:186:in `block (4 levels) in <top (required)>'
Finished in 0.29266 seconds
37 examples, 5 failures
Failed examples:
rspec ./spec/models/user_spec.rb:51 # User model validation: availability of mandatory fields should be valid
rspec ./spec/models/user_spec.rb:135 # User model validation: when email format is valid should be valid
rspec ./spec/models/user_spec.rb:179 # User model validation: return value of authenticate method with valid password
...
这是什么原因,我该如何解决?
感谢您的帮助,
佛瑞德
PS:gemfile
source 'https://rubygems.org'
ruby '2.0.0'
gem 'rails', '4.0.0'
gem 'bootstrap-sass', '2.3.2'
gem 'sass-rails', '~> 4.0.0'
gem 'coffee-rails', '~> 4.0.0'
gem 'uglifier', '2.1.2'
gem 'bcrypt-ruby', '~> 3.0.1'
gem 'jquery-rails', '~> 3.0.4'
gem 'turbolinks', '1.3.0'
gem 'jbuilder', '1.4.2'
group :doc do
gem 'sdoc', '0.3.20', require: false
end
# gem for dev and test only
group :development, :test do
gem 'sqlite3', :require => 'sqlite3'
gem 'annotate', '2.5.0'
gem 'rspec-rails', '2.14.0'
gem 'selenium-webdriver', '2.33.0'
gem 'capybara', '2.1.0'
gem 'factory_girl_rails', '4.2.0'
end
答案 0 :(得分:2)
没有查看所有代码就很难说。
我认为问题出在这里
before { @user.save }
let(:found_user) { User.find_by(email: @user.email) }
当您为密码长度添加验证时,变量@user
变为无效。这意味着found_user为nil(记录未保存且无法找到)。然后你得到undefined method 'authenticate' for nil:NilClass
。
我建议当你真的想要在测试中使用save!
和create!
创建记录时 - 如果有一些问题,你会立即看到它。
同样的原因可能是另一个与身份验证无关但试图在DB中保存无效记录的测试。