如何测试我的Ruby代码在捕获符号时的作用? (RSpec的)

时间:2016-09-22 18:57:44

标签: ruby rspec

我正在制定一个包含几个步骤的销售流程 - 折扣,验证,付款,交付等。如果在此过程中出现问题,我希望能够中止操作,但仍然可以退回销售反对来电者。

代码工作得很好,使用throw / catch(但是我很乐意使用raise / rescue,如果有帮助的话。)问题是测试它 - 理想情况下,我能编写一个测试说“如果出现问题,销售将停止处理”。相反,似乎我能做的最好就是说“如果出现问题,它会抛出:完成”或“如果在第2步出现问题,则不会完成步骤3和4”。有没有其他方法可以实际测试更一般的情况?

这是我正在使用的代码的略微修改版本。使用刘海的方法是可以调用fail!succeed!

的方法
# sale.rb
class Sale
  attr_accessor :status, :amount, :discount_code

  def process!
    catch :done do
      validate_params!
      amount = apply_code!(discount_code)
      verify_delivery!
      charge_money!
      deliver_goods!
    end

    self
  end

  def fail!(error_message: nil)
    Rails.logger.error(error_message)
    status = :failure
    throw :done
  end

  def succeed!
    status = :success
    throw :done
  end
end

我想避免的那种RSpec测试的例子:

# sale_spec.rb
describe 'Sale' do
  describe '#process!' do
    context 'when verification fails' do
      before do
        allow(sale).to receive(:verify_delivery) { sale.fail! }
      end

      it "doesn't charge money" do
        expect(sale).to_not receive(:charge_money!)
        sale.process!
      end

      it "doesn't deliver the goods" do
        expect(sale).to_not receive(:deliver_goods!)
        sale.process!
      end
    end
  end
end

有没有办法可以更普遍地测试这个?

1 个答案:

答案 0 :(得分:1)

我不会为您的特定代码提供解决方案,但我们可以考虑一般的问题。您有一组行动,共同负责销售过程。解决方案是使每个动作独立并使它们流入。如果出错,每个动作都可以恢复。在这种情况下,整个过程将停止在错误指令上,并通过调用其恢复方法来逐步退回操作。所有操作都应该共享一些可以存储对象的上下文(并将它们传递给下一个交互器)。这样,您就可以将流程标记为失败,并稍后可以访问其上下文。

你应该检查一个很棒的lib - https://github.com/collectiveidea/interactor。基本上,您可以将交互器定义为块,然后从这些类中组成一个组织器。它允许您使用FooOrganizer.call(some_context)来返回上下文对象。此上下文对象响应success?failure?方法(您可以在任何交互器内调用context.fail!以停止继续,将进程标记为失败并执行回滚)。您还可以从外部访问上下文中的对象(以便稍后可以访问销售对象)。

在这种方法中,你可以只测试组织者是否成功和/或在其上下文中检查进行中的对象。