Rspec:如何测试私有方法中引发的异常?

时间:2018-10-04 07:52:01

标签: ruby-on-rails ruby ruby-on-rails-3 rspec rspec2

在我的公共方法#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))。引起raise_error(ActiveRecord :: StaleObjectError)        预期的ActiveRecord :: StaleObjectError,但未引发任何情况

请针对在私有方法中引发的异常,建议如何编写单元测试用例。 我根据link使用了send

注意:因为self.lock_version == Product.find(self.id)为false,所以第一次引发了异常。再试一次self.lock_version == Product.find(self.id)为true,因此不会捕获异常。

1 个答案:

答案 0 :(得分:2)

这是您的代码实际工作的简单版本:

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示例应该能够期望代码引发正确的异常类型。