【问题标题】:How to create a ActiveRecord::RecordInvalid for testing?如何创建 ActiveRecord::RecordInvalid 进行测试?
【发布时间】:2014-09-24 18:54:54
【问题描述】:

我有这段代码要测试:

def error_from_exception(ex)
  if ex.is_a?(ActiveRecord::RecordInvalid)
...

要进入 if 块,我需要传入正确的 ex 参数。

如何创建 ActiveRecord::RecordInvalid?

使用 rspec,我正在尝试做这样的事情:

context 'exception is ActiveRecord::RecordInvalid' do
  it 'returns the validation error' do
    begin
      raise ActiveRecord::RecordInvalid
    rescue Exception => ex
      binding.pry
      ###
      # From my pry session:
      # $ ex
      # $ <ArgumentError: wrong number of arguments (0 for 1)>
      # $ ex.class
      # $ ArgumentError < StandardError
      ###
    end


  end
end

如何找出库正在寻找的参数类型?

RecordInvalid link

【问题讨论】:

    标签: ruby-on-rails activerecord rspec


    【解决方案1】:

    以上方法都不适合我,所以我最终在做一个规范时做了以下事情:

    class InvalidRecord
      include ActiveModel::Model
    end
    
    
    raise ActiveRecord::RecordInvalid.new(InvalidRecord.new)
    

    希望对你有帮助!

    【讨论】:

    • 当我不需要任何特定的错误消息而只需要 ActiveRecord::RecordInvalid 对象时,它很有用。
    【解决方案2】:

    编辑:这在 Rails 5.1.1 中是可能的。此提交后不再需要记录参数:https://github.com/rails/rails/commit/4ff626cac901b41f86646dab1939d2a95b2d26bd

    如果您使用的是 5.1.1 以下的 Rails 版本,请参阅下面的原始答案:

    似乎不可能自己提出ActiveRecord::RecordInvalid。如果你看ActiveRecord::RecordInvalid的源码,初始化的时候需要一个记录:

    class RecordInvalid < ActiveRecordError
      attr_reader :record # :nodoc:
      def initialize(record) # :nodoc:
        @record = record
        ...
      end
    end
    

    (来源:https://github.com/rails/rails/blob/master/activerecord/lib/active_record/validations.rb

    解决此问题的方法是简单地创建一个无效的实际记录并尝试使用save! 保存它(例如在需要User.name 时调用User.new.save!)。但是,请记住,如果您使用的模型发生更改并且它在您的测试中变得有效(不再需要User.name),这可能会在未来成为一个问题。

    【讨论】:

    • 是的,这正是我最终要做的。它也适用于有效记录,不会有任何消息。 let!(:user) { FactoryGirl.create(:user) } let!(:ex) { ActiveRecord::RecordInvalid.new(user) }
    【解决方案3】:

    我需要做一些类似的事情来测试我的代码对ActiveRecord::RecordInvalid 的处理。我想做的

    allow(mock_ar_object).to receive(:save!).and_raise(ActiveRecord::RecordInvalid)
    

    但是当 RSpec 尝试实例化 RecordInvalid 时,这会给出 ArgumentError: wrong number of arguments (0 for 1)

    相反,我写了一个RecordInvalid 子类并像这样覆盖initialize

    class MockRecordInvalid < ActiveRecord::RecordInvalid
      def initialize
      end
    end
    
    allow(mock_ar_object).to receive(:save!).and_raise(MockRecordInvalid)
    

    然后rescue ActiveRecord::RecordInvalid 将捕获MockRecordInvalid 并且MockRecordInvalid.new.is_a?(ActiveRecord::RecordInvalid)true

    【讨论】:

    • 它对我有用,我刚刚添加了一个新的message 方法,以便我可以在rescue 部分中执行类似error.message.include?("Kind") 的操作。
    【解决方案4】:

    ActiveRecord::RecordInvalid 需要创建一个对象。 如果您只想测试异常本身,请尝试:

    null_object = double.as_null_object
    ActiveRecord::RecordInvalid.new(null_object)
    

    在这里理解双精度为空对象(https://www.relishapp.com/rspec/rspec-mocks/v/2-6/docs/method-stubs/as-null-object

    【讨论】:

      【解决方案5】:

      我正在使用 update_attribute(attr, 'value') 而不是保存!我可以模拟 update_attribute 方法如下:

      expect(mock_object).to receive(:update_attribute).with(attr, 'value').and_raise(ActiveRecord::RecordInvalid)
      

      【讨论】:

        【解决方案6】:

        我们可以像这样将它存根到模型中,

        ModelName.any_instance.stubs(&lt;method_name&gt;).raises(ActiveRecord::RecordInvalid.new(record))

        示例:

        Post.any_instance.stubs(:save!).raises(ActiveRecord::RecordInvalid.new(post))

        【讨论】:

        • edit您的答案以改进您的代码块(应用格式),并解释其工作原理以及为什么它可以解决问题中描述的问题。见How to Answer
        猜你喜欢
        • 1970-01-01
        • 2012-10-21
        • 2021-11-22
        • 1970-01-01
        • 2012-06-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-05-17
        相关资源
        最近更新 更多