Я бы начал с разбивки сложности вашего метода1 на что-то вроде этого.
private
def stale_object?
self.lock_version == Product.find(self.id).lock_version
end
def attempt_to_rescue_stale_object
if rescue_stale_object_retries =< 3
rescue_stale_object_retries += 1
sleep( 1 + rescue_stale_object_retries)
retry # and the sleep stuff, not sure how you
else
raise Exception.new(timeout.inspect)
end
end
def rescue_stale_object_retries
@rescue_stale_object_retries ||= 0
end
def method_1
begin
raise ActiveRecord::StaleObjectError.new(self, "test") if stale_object?
Product.where(:id => self.id).update_all(attributes)
rescue ActiveRecord::StaleObjectError => e
attempt_to_rescue_stale_object
reload # You can omit the self here
else
raise Exception.new(timeout.inspect)
end
end
end
Теперь вы можете протестировать его так, как вам нравится, сложность логики спасения заключена в метод.Вы не зависите от тестирования фактического поведения в нем (это теперь неактивный вызов, но он может измениться, скажем, на выполнение фонового задания).
[https://relishapp.com/rspec/rspec-mocks/docs/setting-constraints/receive-counts][1] дает нам что-то вроде этого
expect{car_v2}.to receive(:attempt_to_rescue_stale_object).exactly(3).times
car_v2.method1
Еще одно преимущество разбиения сложности на мелкие части состоит в том, что ваше намерение лучше донести до ваших коллег-разработчиков (другого человека).или вы через 6 месяцев забыли о своей первоначальной цели тестирования)