RSpec:如何编写unit testing用例来接收在私有方法中引发的exception

我已经为Race Condition实施了乐观锁定。 为此,我在Product中添加了一个额外的列lock_version 。 方法: recalculate是调用private method_1然后保存( save! )产品。 我不能用save! 在私有method_1 ,因为它将失败其他东西。 我不想重构业务逻辑。

 #Product: Model's new field: # lock_version :integer(4) default(0), not null 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(car_v2).to receive(:method1).and_raise(ActiveRecord::StaleObjectError) end 

当我尝试在测试用例上面编写时,它应该引发Exception ActiveRecord::StaleObjectError 。 但是,我收到的错误就像

  Failure/Error: expect(car_v2).to receive(:set_total_and_buckets_used).and_raise(ActiveRecord::StaleObjectError) ArgumentError: wrong number of arguments (0 for 2) 

你可以这样写:

 expect(ActiveRecord::StaleObjectError).to receive(:new).and_call_original 

因为你正在拯救这个例外

请务必查看https://relishapp.com/rspec/rspec-expectations/docs/built-in-matchers

 expect(car_v2).to receive(:method1).and_raise(ActiveRecord::StaleObjectError) 

意味着当car_v2收到method1你不会调用它,但你会引发一个类型为ActiveRecord::StaleObjectError的exception。 这就是你也收到ArgumentError的原因

使用rspec,您可以检查特定代码是否会引发错误(在您处理的情况下不会处理 – >救援……),如下所示:

 expect { my_cool_method }.to raise_error(ErrorClass)