2

I'm using optimistic locking, and when there is a failure on updating my object, I aim to retry the query until it passes. My problem is that the rescue section is never used on the rspec tests.

The method I'm talking about is the following:

def create_transaction
  amount = -1 * cost_per_word * word_count
  transaction = Transaction.new(amount: amount, processor: :job_done)
  transaction.service = service
  transaction.job = self
  transaction.save!
rescue ActiveRecord::StaleObjectError
  sleep rand
  reload
  retry
end 

The StaleObjectError is generated on transaction.save!, which have a before_create hook which edits other object (in this case, removing money from the object account).

To test it, I could, for example, stub Transaction.new to raise an StaleObjectError, however it would generate an infinite loop.

I also can't test with an approach like

p1 = Person.find(1)
p2 = Person.find(1)

p1.first_name = "Michael"
p1.save

p2.first_name = "should fail"
p2.save # Raises a ActiveRecord::StaleObjectError

Because I'm not testing the before_save hook, I'm testing the create_transaction method. (thanks to @screenmutt for the example)

How can I properly test the rescue section?

fotanus
  • 19,618
  • 13
  • 77
  • 111

2 Answers2

1

First, A StaleObjectError will not be raised when creating an object. It may be raised when editing. See the Docs

p1 = Person.find(1)
p2 = Person.find(1)

p1.first_name = "Michael"
p1.save

p2.first_name = "should fail"
p2.save # Raises a ActiveRecord::StaleObjectError

Testing the Rescue Block

That is what stubs are for, returning a specific value from a method which you may not normally see.

You could also stub save!

RSpec Simple Stub Documentation

Dan Grahn
  • 9,044
  • 4
  • 37
  • 74
  • Thanks, the stale object error happens on other model, in a before_save hook on transaction model (the transaction removes or add money in the other model balance), so I can't use this straight-forward approach. Sorry, I didn't make it clear on the question, let me edit it. – fotanus Aug 20 '13 at 18:49
  • I don't think you are going to be able to time a `StaleObjectError` if it happens in a before save. Unless you could delay the method's save somehow. – Dan Grahn Aug 20 '13 at 18:52
0

The answer I need to be able to test is the unstub method, cited in this answer by Chris Heald

Community
  • 1
  • 1
fotanus
  • 19,618
  • 13
  • 77
  • 111