您現在的位置是:首頁 > 足球

「融雲分析」關於測試驅動開發的一些感悟

  • 由 砍柴網20220503 發表于 足球
  • 2022-08-25
簡介既然 TDD 是軟體工程的一種理論方法,那麼就會有它的適用範圍,短平快的任務應用空間不會太大,TDD 更適合一些大中型、需要長期維護的專案,最好團隊中能有 TDD 經驗的人帶領,如果沒有可以去看看網上一些著名的開源專案是怎麼編寫它的測試程式

utdd是什麼意思

提起測試驅動開發(以下簡稱“TDD”),圈內工程師對其都有一定程度的瞭解,TDD 的優點也得到了普遍的認可。有研究機構曾對微軟和 IBM 的八個開發小組進行了對照測試,結果發現使用了 TDD 的小組比未使用的小組在問題發生比例上減少了四至九成。在結對程式設計的相關實驗中,使用 TDD 的小組比未使用的小組在黑箱測試透過率上平均高出 18%,效果相當明顯。

但反觀日常所接觸的實際工作中,對於 TDD 的使用並不多見,碼農們對其價值也褒貶不一,網上甚至有大咖寫文章公開論述觀點來反對它,這又是為什麼呢?前不久我剛好在融雲的一個專案裡小範圍實踐了一把,我就試著結合各方觀點,斗膽談談自己的體會。

首先介紹一下什麼是 TDD,TDD 最早是由 Kent Beck 提出並在他的《Test-Driven Development By Example》一書中進行詳細闡述的(Kent Beck也是極限程式設計 Extreme Programming 概念的提出者)。書中所述:TDD 就是以測試作為開發過程的中心,要求編寫任何產品程式碼之前,首先編寫用於定義產品程式碼行為的測試,而編寫的產品程式碼又要以使測試透過為目標的軟體工程方法,目的是構造簡單、清晰、高質量的程式碼。

測試是保證軟體質量的重要手段,一個公司的研發部門通常都會有很大比例的測試團隊作為質量保證的堅實後盾。那麼作為開發人員是不是就可以只關心寫程式碼的進度,編譯通過後再跑幾遍沒問題就提交程式碼呢?這樣的程式在碰上初始條件稍有改變,或者壓力、併發等外部因素略有變化下會不會出現崩潰等問題呢?有的團隊會制定規章制度,要求給完成的程式碼編寫測試用例,必須透過才可以提交。這或許能在一定程度上使情況得到改善,但實際效果真的有那麼明顯麼?我就聽過有人抱怨說,完成程式碼後再寫測試用例是浪費時間,因為對邏輯走向已十分了解,測試自然不會有什麼大的紕漏,有那個時間不如多寫幾行程式碼,反正有測試團隊兜底。乍一聽似有道理,但仔細一想實則是在逃避責任,也在浪費公司資源。

那保證軟體質量,有何良策呢?讓我們來看 TDD 是如何做的,前面說過 TDD 的精髓在於將測試前置,這看似微不足道的變化到底會帶來怎樣的化學反應呢?

第一,能夠明確目的。在動手編寫生產程式碼之前,就得先想好這一部分邏輯的輸入輸出是什麼,編寫滿足需求的測試用例,同時增加對需求的強化理解。舉個簡單的例子,與合作開發的同事對好需求,劃分好各自實現的邏輯塊,結果後續聯調時才發現一方理解錯了意思,之前的工作量就白費了。有了這提前編寫的測試程式碼,就能邏輯層面再次明確目標,避免語言文字上的誤解。在編寫程式碼過程中,更容易做到心無旁騖,思緒不會亂飄,因為你的目標就是編寫能透過測試用例的程式碼。當然這一過程可能會需要持續對測試目標進行完善,即所謂的 TDD 微迴圈:測試 -> 實現 -> 重構 -> 測試 。。。

「融雲分析」關於測試驅動開發的一些感悟

第二,強化了模組與介面的概念。再紛繁複雜的業務邏輯也能按功能、層級分為若干業務模組,模組與模組之間透過介面(API)通訊,做好這兩點的設計無形中也就降低了業務邏輯的耦合性,低耦合又是單元測試的前提條件。這樣操作等同於迫使開發者將介面的設計與低耦合性放在第一位去考慮。工作中在接到專案、明確需求後,如何分配任務往往非常考驗團隊人員的綜合能力,拆解顆粒度太粗容易造成邊界不明確;太細又牽扯過多精力,不易實施。但無論怎樣,模組化和明確的介面設計是任務拆解得以順利實施的前提,對將來可能發生的重構也是極好的。

第三,有利於任務的並行展開。當任務拆解分配到個人後,必然有些邏輯是需要前提輸入條件的,比如客戶端需要請求伺服器,那麼在編寫測試用例時就應當提供這樣的前提條件模擬,即 Mock 物件。目前流行的測試框架都帶有 Mock 元件,比如谷歌的 GTest/GMock。有了這些互動物件,無論處在業務流程的哪個階段,都可以馬上展開任務,隨時與上下游模組進行聯調,同時利用各自的單元測試劃分 Bug 歸屬。如果這一步不提前進行,開發任務就要按順序進行,難免出現人員等待的情況。

第四,可以非常高效地進行重構。說起重構,可以說稍大點的專案,因為需求的變化或者邏輯的更新,重構在所難免。有些人就會心裡發怵,生怕會引入新的 bug,甚至陷入重構的泥潭。如果這時有了事前準備好的測試用例,每重構完一塊檢視一下測試結果,就可化風險於無形。

此外 TDD 還很多優點,如快速反饋,測試用例即文件,降低測試團隊負擔等等。聊完了優點,接下來再看看網上大咖們對 TDD 的負面情緒都有哪些。

目前來看最集中的抱怨就是 TDD 會增加時間的投入。TDD 的優勢是建立在高質量測試用例這一前提下的,如果測試程式碼寫的不夠好或者不夠全面就難以覆蓋所有功能點,而“測試 -> 實現 -> 重構”的微迴圈也會帶來不少測試程式碼的開發工作。對於新手來講,耽誤了時間,效果卻很有限,自然動力不足。即便是有信心能使用好 TDD 的團隊,很多時候它的付出回報比也依然不高,尤其在強調迭代速度的網際網路公司,根據時間、質量、花費三者只能取其二的理論,多數情況下也只能捨棄一部分質量來保證研發速度,何況有經驗的團隊即使不用 TDD 也是能保證質量損失在可控範圍內的。

其他的抱怨來自 TDD 的規則太教條化,比如它的三大定律:

1。 在編寫不能透過的單元測試前,不可編寫生產程式碼。

2。 只可編寫剛好無法透過的單元測試,不能編譯也算不透過。

3。 只可編寫剛好滿足以通過當前失敗測試的生產程式碼。

這一點關鍵看怎麼理解,有個博主說的就很好 “Learn the rules, THEN break them。” 一旦理解了定律所表達的真實含義,是可以根據實際情況靈活變通的。

下面來談談個人對 TDD 一些膚淺的看法。

既然 TDD 是軟體工程的一種理論方法,那麼就會有它的適用範圍,短平快的任務應用空間不會太大,TDD 更適合一些大中型、需要長期維護的專案,最好團隊中能有 TDD 經驗的人帶領,如果沒有可以去看看網上一些著名的開源專案是怎麼編寫它的測試程式碼的,學習高手寫的程式碼,每看一次都非常受益。

另外極限程式設計的一些理念,比如 KISS(Keep It Simple, Stupid),YAGNI(You Aren‘t Gonna Need It)與 TDD 結合起來也很值得玩味。這也不難理解,XP 和 TDD 本來就是一個人提出的理論。無論寫程式碼還是寫測試用例,這些原則性的東西,最好能貫徹。

最後再說一些程式設計方面的經驗吧,最近這個專案給我印象最深的就是斷言的使用。不僅是在測試用例中用來判斷結果與期望值是否相符,更多是要在程式的關鍵位置埋好斷言,將風險扼殺在搖籃之中。比如開原始碼 WebRTC 在核心類的方法中就大量使用了斷言,判斷呼叫執行緒是否正確,關鍵值是否符合要求等。這類錯誤可能會在程式執行到後面某個點才暴露出來,相同原因導致的現象多種多樣,如果不及時發現,會大大增加 Debug 的成本。

所以我的建議就是斷言要大膽的加,甚至允許在 Release 版本中的關鍵位置存在斷言,這樣使用者在反饋問題時,就能正確歸因,及時解決改進。

Top