具有多个断言的RSpec单元测试

时间:2014-07-31 03:18:43

标签: ruby-on-rails unit-testing ruby-on-rails-4 rspec rspec3

首先,我知道在单元测试中有多个断言是不好的做法。

但有时你需要测试一些原子事务。作为一个简化示例,让我们来看一些具有Account类的银行应用程序:

class Account 
  attr_accessor :balance

  def transfer(to_account, amount)
    self.balance -= amount
    to_account.balance += amount
    Audit.create(message: "Transferred #{amount} from #{self.number} to #{to_account.number}."
  end

end

在这种情况下,我想一起检查3件事:

  1. 来源帐户余额减少amount
  2. 目标帐户余额增加amount
  3. 已插入审核记录
  4. 测试@account.transfer方法的最佳方法是什么?

2 个答案:

答案 0 :(得分:2)

在这种情况下,我想一起检查3件事:

我认为你真正想要的是在某些条件下描述这些事物的行为,从而确保行为符合你的规范。这可能意味着事情一起发生;或者它可能意味着某些事情只发生在一组条件而不是其他条件中,或者一个异常导致所有事情都回滚到其原始状态。

除了让事情变得更快之外,在一次测试中拥有所有断言是没有魔力的。 除非您面临严重的性能损失(通常在全栈测试中发生),否则每次测试使用一个断言要好得多。

RSpec可以直接提取测试设置阶段,以便为每个示例重复:

class Account 
  attr_accessor :balance

  def transfer(to_account, amount)
    self.debit!(amount)
    to_account.credit!(amount)
    Audit.create!(message: "Transferred #{amount} from #{self.number} to #{to_account.number}."
  rescue SomethingBadError
    # undo all of our hard work
  end

end

describe Account do
  context "when a transfer is made to another account" do
    let(:other_account} { other_account }
    context "and the subject account has sufficient funds" do
      subject { account_with_beaucoup_bucks }
      it "debits the subject account"
      it "credits the other account"
      it "creates an Audit entry"
    end
    context "and the subject account is overdrawn" do
      subject { overdrawn_account }
      it "does not debit the subject account"
      it "does not credit the other account"
      it "creates an Audit entry" # to show the attempted transfer failed
    end
  end
end

如果“快乐路径”中的所有三个测试都通过了,那么它们都“一起发生”,因为初始系统状态在每种情况下都是相同的。

但是,当出现问题时,您还需要确保不会发生的事情,并且系统会恢复到原始状态。有多个断言可以很容易地看到它按预期工作,当测试失败时,确切 它们失败了。

答案 1 :(得分:1)

每次测试多个断言并不总是坏习惯。如果多个断言验证了相同的行为,那么它就没有问题。尝试在同一测试中验证多个行为时存在问题。 当然,每次测试有多个断言存在一些风险。其中之一是您可能会意外地从以前的测试集中保留值,这会以奇怪的方式使先前的测试无效。 此外,当一个断言为假时,所有其他断言都不会被执行,这可能会导致难以理解发生了什么。但要合理,你可以有多个断言断言相同的行为,最好是短行为,没有额外的设置。

在你带来的简单案例中,我会使用多个断言,因为它非常简单。但当然它可以变得更复杂,比如负余额,不同类型的账户和东西。那么最好使用一个(最好的)断言进行不同的测试。我会像这样组织它:

  • 1来测试当前账户的行为(最简单的情况);
  • 1到方法可以拥有的每个不同路径(例外,否定 平衡等);
  • 1在所有这些可能性中测试审核;

  • 1来测试当前to_account的行为(最简单的情况);

  • 1到该方法可以具有的每个不同路径。 (例外,否定 平衡等);
  • 1在每种可能性中测试审核;

由于审核测试非常简单,无需额外设置,因此您还可以将其与Account和to_account一起进行测试。

相关问题