Shoulda::Matchers::ActiveModel::AllowValueMatcher::CouldNotSetAttributeError

Shoulda::Matchers::ActiveModel::AllowValueMatcher::CouldNotSetAttributeError

class User
  #...
  validates :debit_card_status_change_date,
    timeliness: { type: :date, allow_blank: true }
  #...
end

规格:

it { is_expected.to allow_value(nil).for(:debit_card_status_change_date) }
it { is_expected.to allow_value("").for(:debit_card_status_change_date) }
it { is_expected.not_to allow_value("abc").for(:debit_card_status_change_date) }

为什么第二次和第三次测试会失败?

Failure/Error: it { is_expected.to allow_value("").for(:debit_card_status_change_date) }
  Shoulda::Matchers::ActiveModel::AllowValueMatcher::CouldNotSetAttributeError:
    Expected Class to be able to set debit_card_status_change_date to "", but got nil instead.

Failure/Error: it { is_expected.not_to allow_value("abc").for(:debit_card_status_change_date) }
  Shoulda::Matchers::ActiveModel::AllowValueMatcher::CouldNotSetAttributeError:
    Expected Class to be able to set debit_card_status_change_date to "abc", but got nil instead.

在从 rails4.0、rspec 2 和 shoulda-matchers 2.x.x 升级到 rails 4.2、rspec 3.3.1 和 shoulda 之前一切正常-匹配器 3.0

抱歉,您在使用最新版本时遇到问题。

从 3.0 开始,如果您提供给匹配器的值与模型在执行验证时实际使用的值不相同,allow_value 将引发错误。在这种情况下,您试图在最终将这些值类型转换为 nil 的列上设置 """abc"(因为它是日期列)。这些都是根本不同的值,所以匹配器会感到困惑,不知道如何解释。

你有两个解决方案:

  1. 删除 """abc" 的测试。由于这些被转换为零,你基本上重复了两次相同的测试。
  2. 如果你想保留这些测试,你可以在末尾添加 ignore_interference_by_writer(在 for 之后),这将告诉匹配器忽略任何值更改。