如何测试ActiveRecord中哪些validation失败?

我有这样的模型:

class User  (2..5) end 

我想测试一下这个validation:

 it "should not allow too short name" do u = User.new(:name => "a") u.valid? u.should have(1).error_on(:name) end 

但是它没有测试在name设置了哪种错误。 我想知道,如果是too_shorttoo_long ,或者其他一些validation失败了。

我可以在errors数组中查找消息文本,如下所示:

 u.errors[:name].should include(I18n.t("activerecord.errors.models.user.attributes.name.too_short")) 

但是当我在locale文件中设置activerecord.errors.messages.too_short而不是特定于模型的消息时,这将失败。

那么,是否可以检查出现了哪种错误?

Rails 在2011年末和Rails v3.2中添加了一种查询ActiveModel错误的方法 。 只是检查一下#added?是否有相应的错误#added?

 # An error added manually record.errors.add :name, :blank record.errors.added? :name, :blank # => true # An error added after validation record.email = 'taken@email.com' record.valid? # => false record.errors.added? :email, :taken # => true 

请注意,对于参数化的validation(例如:greater_than_or_equal_to ),您还需要传递参数的值。

 record.errors.add(:age, :greater_than_or_equal_to, count: 1) record.errors.added?(:age, :greater_than_or_equal_to, count: 1) 

错误由他们的i18n密钥识别。 您可以在错误部分下找到适当的密钥,以检查相应的Rails i18n文件中的任何语言。

你可以问一些其他漂亮的问题ActiveModel#Error#empty?#include?(attr) ,以及任何你可以问一个Enumerable

我真的不喜欢在错误哈希中查找已翻译的错误消息的想法。 在与Rubyists的对话后,我结束了猴子修补错误哈希,因此它首先保存了未翻译的消息。

 module ActiveModel class Errors def error_names @_error_names ||= { } end def add_with_save_names(attribute, message = nil, options = {}) message ||= :invalid if message.is_a?(Proc) message = message.call end error_names[attribute] ||= [] error_names[attribute] << message add_without_save_names(attribute, message, options) end alias_method_chain :add, :save_names end end 

然后你可以这样测试:

 u = User.new(:name => "a") u.valid? u.errors.error_names[:name].should include(:too_short) 

我建议检查gem shoulda来处理这些类型的重复validation测试。 它补充了RSpec或Test :: Unit,因此您可以编写简明的规范,例如:

 describe User do it { should ensure_length_of(:name).is_at_least(2).is_at_most(5) } end 

我使用的方法:

 it "should not allow too short name" do u = User.new(:name => "a") expect{u.save!}.to raise_exception(/Name is too short/) end 

我使用正则表达式来匹配exception消息,因为exception消息中可能有许多validation消息,但我们希望确保它包含与名称太短相关的特定代码段。

这种方法会将您的断言与validation消息结合起来,因此如果您每次修改validation消息,您可能也需要修改您的规范。 总的来说,这是断言validation正在完成其工作的一种简单方法。