Rspec: Как проверить исключение, которое вызывается в приватном методе? - PullRequest
0 голосов
/ 04 октября 2018

В моем публичном методе #recalculate, вызывая приватный method1.Этот метод вызывает исключение 'ActiveRecord :: StaleObjectError'.

def recalculate
  method_1
  self.save!
end

private
def method_1
    begin
      ####
      ####
      if self.lock_version == Product.find(self.id).lock_version
         Product.where(:id => self.id).update_all(attributes)
      else
         raise ActiveRecord::StaleObjectError.new(self, "test")
      end
    rescue ActiveRecord::StaleObjectError => e
        if tries < 3
           tries += 1
           sleep(1 + tries)
           self.reload
           retry
        else
           raise Exception.new(timeout.inspect)
        end
    end
end

Контрольный пример Rspec:

  it 'if car is updated then ActiveRecord::StaleObjectError should be raised' do
    prod_v1 =Product.find(@prod.id)
    prod_v2 = Car.find(@prod.id)
    prod_v1.recalculate
    prod_v1.reload  # will make lock_version of prod_v1 to 1

    prod_v2.recalculate # howvever lock_version of prod_v2 is still 0.

    expect{ prod_v2.send(:method1)}.to raise_error(ActiveRecord::StaleObjectError)

Ошибка:

Ошибка / Ошибка: ожидаемо (prod_v2.send (: method1)). To yield_error (ActiveRecord:: StaleObjectError) ожидается ActiveRecord :: StaleObjectError, но ничего не поднято

Пожалуйста, предложите, как написать пример модульного теста для исключения, которое вызывается в приватном методе.Я использовал send на основе ссылки :

Примечание: впервые возникла исключительная ситуация, поскольку self.lock_version == Product.find (self.id) был ложным.И при повторных попытках self.lock_version == Product.find (self.id) имеет значение true, поэтому исключение не захватывается.

1 Ответ

0 голосов
/ 04 октября 2018

Вот более простая версия того, что на самом деле делает ваш код:

class StaleObjectError < Exception
end

class MyClass
  def initialize
    @tries = 0
  end

  def method_1
    begin
      raise StaleObjectError.new("I'm the more specific exception")
    rescue StaleObjectError => e
      if @tries < 3
        @tries += 1
        sleep(1 + @tries)
        retry
      else
        raise Exception.new("I'm the failure case")
      end
    end
  end

end

myObject = MyClass.new

begin
  myObject.method_1
rescue Exception => e
  # in the error condition, this is always #<Exception: I'm the failure case>
  puts e.inspect
end

Что приводит к

#<Exception: I'm the failure case>

Вы не сможете ожидать ActiveRecord::StaleObjectError, потому что вызамаскируйте его своим спасением - вы преобразовали StaleObjectError в Exception

Если вы хотите сохранить StaleObjectError, тогда вы можете вместо этого raise e в вашем спасении.Итак, чтобы использовать мой пример кода снова:

if @tries < 3
  @tries += 1
  sleep(1 + @tries)
  retry
else
  raise e
end

Что приведет к

#<StaleObjectError: I'm the more specific exception>

Тогда ваш пример rspec должен ожидать, что код вызовет правильный тип исключения.

...