[英]RSpec unit test with multiple assertions
首先,我知道在单元测试中有多个断言是不好的做法。
但有时你需要测试一些原子事务。 作为一个简化示例,让我们来看一些具有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件事:
amount
减少 amount
增加 测试@account.transfer
方法的最佳方法是什么?
在这种情况下,我想一起检查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测试当前to_account的行为(最简单的情况);
由于Audit测试非常简单,无需额外设置,因此您还可以使用Account和to_account进行测试。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.