在 1998 年,Kent Beck 編寫了 sUnit,一個(gè)面向 SmallTalk 的單元測(cè)試框架。之后,他將這個(gè)框架移植到 JAVA,即 jUnit。從那時(shí)起,xUnit 框架擴(kuò)展到那些最流行的編程語言。比較新的語言,如 Golang 和 Rust,已經(jīng)將測(cè)試直接合并到編譯器和標(biāo)準(zhǔn)庫中。
但是單元測(cè)試并不是唯一。還有集成測(cè)試和性能測(cè)試等等。在我看來,集成測(cè)試和單元測(cè)試是健壯軟件的基石。因此,今天讓我們看看單元測(cè)試與集成測(cè)試之間的區(qū)別,以及你什么時(shí)候該選擇哪種測(cè)試。
什么是一個(gè)單元?
一個(gè)單元是邏輯上分離的最小代碼塊
單元測(cè)試是一種孤立地測(cè)試盡可能小的代碼片段的測(cè)試。那么,什么是一個(gè)單元?
術(shù)語“單元”來自數(shù)學(xué)。數(shù)字 1 被認(rèn)為是單元,因?yàn)樗亲钚〉淖匀粩?shù)。它是最小的正整數(shù)。以此類推,你源代碼的一個(gè)單元就是邏輯上與其余代碼分離的最小代碼片段。它是一個(gè)完整的且邏輯上不同的代碼片段,而且是最小的部分。
在大多數(shù)編程語言中,你的單元會(huì)是一個(gè)函數(shù)或方法調(diào)用。
單元測(cè)試的好處是,如果你的代碼由獨(dú)立的小片段組成,那么,為它們編寫測(cè)試就相當(dāng)容易。這種易編寫性意味著你可以在開發(fā)功能時(shí)完成單元測(cè)試。
與其它形式的測(cè)試相比,單元測(cè)試的執(zhí)行時(shí)間相當(dāng)短。這意味著你可以頻繁運(yùn)行單元測(cè)試。隨著軟件的成熟,一套單元測(cè)試是防止回歸和降低維護(hù)成本的有力工具。
追溯單元測(cè)試
在考慮將單元測(cè)試添加到現(xiàn)有軟件時(shí),需要考慮成本和收益。
單元測(cè)試的一個(gè)關(guān)鍵假設(shè)是,被測(cè)試的軟件很容易分成不同的單元。在沒有考慮單元測(cè)試編寫的軟件中,這個(gè)假設(shè)很少成立。向現(xiàn)有軟件添加單元測(cè)試通常是一種非常好的方法,來穩(wěn)定軟件并防止將來回歸,但是重構(gòu)代碼來支持簡單的單元測(cè)試可能需要大量工作,甚至?xí)胄碌娜毕荨T诳紤]將單元測(cè)試添加到現(xiàn)有軟件時(shí),需要考慮成本和收益。如果你的代碼正在工作,如果代碼很少需要修改,如果代碼不容易進(jìn)行單元測(cè)試,那么加入單元測(cè)試的好處可能無法保證成本。在這些情況下,可以依靠集成測(cè)試來防止該領(lǐng)域的缺陷。
什么是集成測(cè)試?
集成測(cè)試聚焦于整個(gè)軟件棧
如果單元測(cè)試的哲學(xué)是基于這樣一種認(rèn)識(shí),即測(cè)試小的獨(dú)立代碼片段是防止回歸的一種好方法,那么集成測(cè)試是基于這樣一種理解,即事情通常在邊緣狀態(tài)出錯(cuò)。外部世界是一個(gè)混亂的地方,它與你代碼交互的地方通常是意外發(fā)生的地方。
你可以通過單元測(cè)試實(shí)現(xiàn) 100%代碼覆蓋率,但仍然發(fā)現(xiàn)你的軟件失敗。你可能試圖從錯(cuò)誤的位置讀取文件,或者你的軟件可能從一個(gè)調(diào)用的服務(wù)得到預(yù)期之外的輸出,或者它可能以一種無效的方式調(diào)用數(shù)據(jù)庫。
盡管單元測(cè)試應(yīng)該快速運(yùn)行并且數(shù)量眾多,但是一個(gè)好的集成測(cè)試策略應(yīng)該關(guān)注較少數(shù)量的高影響測(cè)試。
這些測(cè)試應(yīng)該跨越單元測(cè)試無法跨越的所有界限,寫入文件系統(tǒng),接觸外部資源,等等。
當(dāng)集成測(cè)試棘手時(shí)
某些外部系統(tǒng)確實(shí)很難集成到測(cè)試中。這是因?yàn)樗鼈冊(cè)诂F(xiàn)實(shí)世界中有著無法消除的副作用:金融交易、電子郵件發(fā)送、物理移動(dòng)一個(gè)噴漆機(jī)器人等。在你在測(cè)試中放棄并避開它們之前,找找解決方案。
許多外部系統(tǒng)有一個(gè)文檔化的方法來在集成測(cè)試中使用它們。支付處理程序通常有測(cè)試信用卡號(hào),可以設(shè)置具有測(cè)試郵箱賬戶的測(cè)試用戶來測(cè)試郵件發(fā)送。
集成測(cè)試越接近真實(shí)世界的交互,就越有可能發(fā)現(xiàn)問題并提供真正的價(jià)值。
Amazon SES——Test email addresses
Paypal——Test credit card numbers
UPS——Test api mode
一個(gè)電子商務(wù)例子
假設(shè)你正在編寫一個(gè)簡單的電商網(wǎng)站,一個(gè)簡化版的 amazon.com。這里的細(xì)節(jié)很重要,所以我們假設(shè),你會(huì)使用 PostgreSQL 作為你的數(shù)據(jù)存儲(chǔ),使用 PayPal 進(jìn)行支付,使用 UPS 進(jìn)行發(fā)貨、使用 Amazon Simple Email Service 來發(fā)送電子發(fā)票郵件。
單元測(cè)試:
單元測(cè)試策略將以一種孤立的方式測(cè)試應(yīng)用程序的邏輯。這可能包括:
- 測(cè)試稅費(fèi)計(jì)算邏輯是否正確地計(jì)算出各個(gè)司法管轄區(qū)的稅費(fèi)
- 測(cè)試放置到購物車數(shù)據(jù)結(jié)構(gòu)中的項(xiàng)目是否被正確添加
- 測(cè)試折扣代碼是否被正確使用
這些領(lǐng)域中的每一個(gè)都可能有幾個(gè)測(cè)試。每個(gè)測(cè)試將驗(yàn)證一小部分功能。單元測(cè)試的能力來自它們的數(shù)量、簡單性以及它們的執(zhí)行速度和便捷性。
集成測(cè)試:
另一方面,你的集成測(cè)試將專注于測(cè)試你的電子商務(wù)代碼與其它系統(tǒng)的交互。這意味著不僅要測(cè)試與數(shù)據(jù)存儲(chǔ)的集成,還要測(cè)試與郵件發(fā)送服務(wù)的集成、與支付服務(wù)的集成等等。這些可能包括:
- 測(cè)試是否可以從外部運(yùn)輸服務(wù)中檢索運(yùn)輸費(fèi)率
- 測(cè)試發(fā)票是否可以生成并正確發(fā)送
- 測(cè)試訂單信息是否可以持久化并從數(shù)據(jù)存儲(chǔ)中正確檢索
- 測(cè)試交易是否可以發(fā)送并被支付處理程序正確處理
這些功能中的每一個(gè)都可能需要一個(gè)或兩個(gè)集成測(cè)試來驗(yàn)證。這些測(cè)試運(yùn)行起來會(huì)比較慢,可能涉及一些安裝和拆卸步驟。結(jié)果是,每個(gè)測(cè)試的代碼覆蓋率會(huì)相當(dāng)大。這些測(cè)試將通過捕獲單元測(cè)試不能捕獲的問題來產(chǎn)生價(jià)值。然而,維護(hù)成本和執(zhí)行時(shí)間可能會(huì)比較高。
集成測(cè)試 vs 單元測(cè)試
是時(shí)候正面比較了
那么,應(yīng)該首選哪種類型的測(cè)試呢?單靠兩者中的任一個(gè)都是不夠的。這兩者都是綜合測(cè)試計(jì)劃的一部分。讓我們直接比較一下:
基于理想化測(cè)試的工作軟件
每種情況都是獨(dú)特的,基于在其它情況下有效的建議不應(yīng)盲目遵循。
現(xiàn)在我們明白了,單元測(cè)試不應(yīng)該觸及文件系統(tǒng),而集成測(cè)試應(yīng)該只集成松散的組件。但實(shí)際上,將測(cè)試劃分為兩個(gè)明確的類別有點(diǎn)太簡單了,如果我們只關(guān)注定義,我們就會(huì)忽略目標(biāo),即正確的工作軟件。
一些非常有想法的開發(fā)者認(rèn)為單元測(cè)試可以并且應(yīng)該讀寫數(shù)據(jù)庫。其它人則認(rèn)為單元測(cè)試是一種浪費(fèi),粗粒度的集成測(cè)試提供的價(jià)值最大。
問題是,每種情況都是獨(dú)特的,基于在其它情況下有效的建議不應(yīng)盲目遵循。需要牢記的一個(gè)問題是,這個(gè)測(cè)試要捕獲什么類型的缺陷。如果每個(gè)測(cè)試都是經(jīng)過深思熟慮編寫來提升軟件可靠性的,如果測(cè)試在不再有價(jià)值時(shí)被刪除,那么隨著時(shí)間的推移,將發(fā)現(xiàn)為特定項(xiàng)目提供最大價(jià)值的特定測(cè)試方法。
原文鏈接:
https://blog.earthly.dev/unit-vs-integration/






