【问题标题】:How to test method retry on optimistic locking without getting an inifite loop?如何在没有无限循环的情况下测试方法重试乐观锁定?
【发布时间】:2013-08-22 22:22:13
【问题描述】:

我正在使用乐观锁定,当更新我的对象失败时,我的目标是重试查询,直到它通过。我的问题是救援部分从未用于 rspec 测试。

我说的方法如下:

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 

StaleObjectError 是在 transaction.save! 上生成的,它有一个 before_create 钩子,用于编辑其他对象(在这种情况下,从对象帐户中移除资金)。

为了对其进行测试,例如,我可以存根 Transaction.new 以引发 StaleObjectError,但它会生成无限循环。

我也无法使用类似的方法进行测试

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

因为我没有测试before_save 挂钩,所以我正在测试create_transaction 方法。 (感谢@screenmutt 的例子)

如何正确测试救援部分?

【问题讨论】:

  • 为什么存根看起来不正确?这就是我会做的,或多或少。
  • @SergioTulentsev 如果可能的话,我宁愿找到一种真正产生错误的方法。如果我的代码从不自己抛出 StableObjectError 怎么办?
  • 这是两个不同的测试:测试是否可以引发错误,以及测试如果引发错误,是否正确处理。
  • @SergioTulentsev 所以也许我的问题是如何测试是否可以引发错误?
  • @SergioTulentsev 我不能存根,因为它会导致无限循环。

标签: ruby rspec


【解决方案1】:

我需要能够测试的答案是unstub 方法,引用于this answer by Chris Heald

【讨论】:

    【解决方案2】:

    首先,StaleObjectError 在创建对象时不会被引发。编辑时可能会提出。 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
    

    测试救援块

    这就是存根的用途,从您通常看不到的方法返回特定值。

    你也可以存根save!

    RSpec Simple Stub Documentation

    【讨论】:

    • 谢谢,陈旧对象错误发生在其他模型上,在交易模型的 before_save 钩子中(交易在其他模型余额中删除或添加钱),所以我不能直接使用这个方法。抱歉,我没有把问题说清楚,让我编辑一下。
    • 如果StaleObjectError 发生在保存前,我认为您将无法计时。除非你能以某种方式延迟方法的保存。
    猜你喜欢
    • 1970-01-01
    • 2014-05-28
    • 1970-01-01
    • 2021-11-19
    • 1970-01-01
    • 2018-12-31
    • 1970-01-01
    • 2020-01-25
    • 2017-10-30
    相关资源
    最近更新 更多