Rspec 和 Devise 4.2:过去有效的模型测试中的 ArgumentError
Rspec and Devise 4.2: ArgumentError in model test that used to work
Rails 5 现已发布,我正在升级我的基本 login/CRUD 应用程序以使用新框架,这也涉及将 Devise 更新到 4.2。事情非常简单,除了一个 rspec
测试失败。我尝试使用 pry
单步执行代码,但发现问题超出了我的范围。任何指针将不胜感激。
这是错误:
Failures:
1) User email rejects email addresses with improper format
Failure/Error: expect(user).not_to be_valid
ArgumentError:
wrong number of arguments (given 0, expected 1)
# ./spec/models/problem_test_user_spec.rb:13:in `block (4 levels) in <top (required)>'
# ./spec/models/problem_test_user_spec.rb:11:in `each'
# ./spec/models/problem_test_user_spec.rb:11:in `block (3 levels) in <top (required)>'
这是精简的测试:
1 require 'rails_helper'
2 require 'devise'
3
4 RSpec.describe User, type: :model do
5 let (:user) { FactoryGirl.create :user }
6
7 describe "email" do
8 it "rejects email addresses with improper format" do
9 invalid_addresses = %w[ user@example,com user_at_foo.org user.name@example. ]
10
11 invalid_addresses.each do |addr|
12 user.email = addr
13 expect(user).not_to be_valid
14 end
15 end
16 end
17 end
这是我的模型:
class User < ApplicationRecord
devise :database_authenticatable, :validatable
validates :email, length: { maximum: 254 } # max length per RFC 3696, errata ID 1690
end
这是我的工厂:
FactoryGirl.define do
factory :user do
name { Faker::Name.name }
tone_name { "#{Faker::Company.name} Tone" }
email { Faker::Internet.email }
password SOME_PASSWORD
password_confirmation SOME_PASSWORD
admin false
end
end
一个后记:该应用程序在我的开发环境中运行良好,但它将允许 name@example,com
形式的无效密码,其中 rails 4.2 版本通过了 rspec
测试并且捕获此无效密码并出错。
另一个线索:我了解到 Devise 在 v4.1 中将默认的 email_regexp
更改为不太严格的表达式。我的测试实际上失败了,因为现在接受了一个以前被识别为非法的电子邮件地址。 ArgumentError
不在我的代码中。我认为这是 Devise 或 Rspec 中的错误。如果我在我的测试中放置一个 binding.pry
,那么我的模型上一个简单的 #inspect
会导致以下结果:
12: invalid_addresses.each do |addr|
13: user.email = addr
14: binding.pry
=> 15: expect(user).not_to be_valid
16: end
17: end
18: end
19: end
[1] pry(#<RSpec::ExampleGroups::User::Email>)> user.inspect
ArgumentError: wrong number of arguments (given 0, expected 1)
from /Users/tarsa/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/devise-4.2.0/lib/devise/models/database_authenticatable.rb:146:in `password_digest'
Devise 代码看起来没有问题,我怀疑正在与 ActiveRecord 进行一些交互,但此时我的调试技巧已达到极限。
我可以通过将 Devise 配置为使用 email_regexp
的 4.0.3 版本来解决这个问题。如果所有的密码字符串都被识别为无效,那么这个错误,无论它在哪里,都不会被挠痒痒。
问题不是 Rails 5 的问题,而是由于我在我的模型中继续使用 password_digest
造成的,它最初是用 ActiveRecord 验证的。当我切换到 Devise 时,我将这个属性留在 table 中。从 Devise 4.2.0 开始,完成验证的机制已更改为使用 serializable_hash
并且试图调用残留的 password_digest
属性作为方法,从而导致错误。
删除字段解决了问题,测试失败并显示正确的消息。
感谢 Devise 的人们对此的洞察力。
Rails 5 现已发布,我正在升级我的基本 login/CRUD 应用程序以使用新框架,这也涉及将 Devise 更新到 4.2。事情非常简单,除了一个 rspec
测试失败。我尝试使用 pry
单步执行代码,但发现问题超出了我的范围。任何指针将不胜感激。
这是错误:
Failures:
1) User email rejects email addresses with improper format
Failure/Error: expect(user).not_to be_valid
ArgumentError:
wrong number of arguments (given 0, expected 1)
# ./spec/models/problem_test_user_spec.rb:13:in `block (4 levels) in <top (required)>'
# ./spec/models/problem_test_user_spec.rb:11:in `each'
# ./spec/models/problem_test_user_spec.rb:11:in `block (3 levels) in <top (required)>'
这是精简的测试:
1 require 'rails_helper'
2 require 'devise'
3
4 RSpec.describe User, type: :model do
5 let (:user) { FactoryGirl.create :user }
6
7 describe "email" do
8 it "rejects email addresses with improper format" do
9 invalid_addresses = %w[ user@example,com user_at_foo.org user.name@example. ]
10
11 invalid_addresses.each do |addr|
12 user.email = addr
13 expect(user).not_to be_valid
14 end
15 end
16 end
17 end
这是我的模型:
class User < ApplicationRecord
devise :database_authenticatable, :validatable
validates :email, length: { maximum: 254 } # max length per RFC 3696, errata ID 1690
end
这是我的工厂:
FactoryGirl.define do
factory :user do
name { Faker::Name.name }
tone_name { "#{Faker::Company.name} Tone" }
email { Faker::Internet.email }
password SOME_PASSWORD
password_confirmation SOME_PASSWORD
admin false
end
end
一个后记:该应用程序在我的开发环境中运行良好,但它将允许 name@example,com
形式的无效密码,其中 rails 4.2 版本通过了 rspec
测试并且捕获此无效密码并出错。
另一个线索:我了解到 Devise 在 v4.1 中将默认的 email_regexp
更改为不太严格的表达式。我的测试实际上失败了,因为现在接受了一个以前被识别为非法的电子邮件地址。 ArgumentError
不在我的代码中。我认为这是 Devise 或 Rspec 中的错误。如果我在我的测试中放置一个 binding.pry
,那么我的模型上一个简单的 #inspect
会导致以下结果:
12: invalid_addresses.each do |addr|
13: user.email = addr
14: binding.pry
=> 15: expect(user).not_to be_valid
16: end
17: end
18: end
19: end
[1] pry(#<RSpec::ExampleGroups::User::Email>)> user.inspect
ArgumentError: wrong number of arguments (given 0, expected 1)
from /Users/tarsa/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/devise-4.2.0/lib/devise/models/database_authenticatable.rb:146:in `password_digest'
Devise 代码看起来没有问题,我怀疑正在与 ActiveRecord 进行一些交互,但此时我的调试技巧已达到极限。
我可以通过将 Devise 配置为使用 email_regexp
的 4.0.3 版本来解决这个问题。如果所有的密码字符串都被识别为无效,那么这个错误,无论它在哪里,都不会被挠痒痒。
问题不是 Rails 5 的问题,而是由于我在我的模型中继续使用 password_digest
造成的,它最初是用 ActiveRecord 验证的。当我切换到 Devise 时,我将这个属性留在 table 中。从 Devise 4.2.0 开始,完成验证的机制已更改为使用 serializable_hash
并且试图调用残留的 password_digest
属性作为方法,从而导致错误。
删除字段解决了问题,测试失败并显示正确的消息。
感谢 Devise 的人们对此的洞察力。