How do I create an ActiveRecord :: RecordInvalid for testing?

I have this piece of code that I am trying to test:

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

      

To get into the if block, I need to enter the correct ex

param.

How do I create an ActiveRecord :: RecordInvalid?

With rspec, I'm trying to do something like this:

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

      

How do you know what type of argument the library is looking for?

RecordInvalid link

+5


source to share


5 answers


EDIT: This is now possible in Rails 5.1.1. The write argument is no longer required after this commit: https://github.com/rails/rails/commit/4ff626cac901b41f86646dab1939d2a95b2d26bd

If you are on a Rails version under 5.1.1 see the original answer below:

Doesn't look like you can lift it ActiveRecord::RecordInvalid

yourself. If you look at the source code for ActiveRecord::RecordInvalid

, the initialization requires the entry:



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

      

(source: https://github.com/rails/rails/blob/master/activerecord/lib/active_record/validations.rb )

Something you could do to work around this would be to simply create an actual entry that is invalid and try to store it with save!

(like calling User.new.save!

when required User.name

). However, keep in mind that this could potentially become a problem in the future if the model you are using is changed and becomes valid in your test ( User.name

no longer required).

+3


source


ActiveRecord :: RecordInvalid needs an object to be created. If you only want to test the exception itself, try:

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

      



Understand double object as null object here ( https://www.relishapp.com/rspec/rspec-mocks/v/2-6/docs/method-stubs/as-null-object )

0


source


I needed to do something similar to test my code handling ActiveRecord::RecordInvalid

. I wanted to do

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

      

but it gives ArgumentError: wrong number of arguments (0 for 1)

when RSpec tries to instantiate RecordInvalid

.

Instead, I wrote a subclass RecordInvalid

and redid it initialize

like this:

class MockRecordInvalid < ActiveRecord::RecordInvalid
  def initialize
  end
end

allow(mock_ar_object).to receive(:save!).and_raise(MockRecordInvalid)

      

Then a rescue ActiveRecord::RecordInvalid

will catch MockRecordInvalid

and MockRecordInvalid.new.is_a?(ActiveRecord::RecordInvalid)

- true

.

0


source


None of the above methods worked for me, so I finally did the following when executing the spec:

class InvalidRecord
  include ActiveModel::Model
end


raise ActiveRecord::RecordInvalid.new(InvalidRecord.new)

      

Hope it helps!

0


source


I am using update_attribute (attr, 'value') instead of save! and I can simulate the update_attribute method like this:

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

      

0


source







All Articles