[英]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.