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 的人们对此的洞察力。