為了可測性而設計

vr862410 7年前發布 | 26K 次閱讀 單元測試 軟件測試

2016年3月,來自 Stripe 的 Nelson Elhage 在他的博客上與我們分享了他在實際工作當中探索總結出來的一些關于可測性代碼的設計原則。Nelson在文章中闡述了代碼可測性的重要性和它為軟件質量提升所帶來的好處,并列出了可測性代碼的一些特點。

在設計軟件項目時,我們總是會面臨很多結構性方面的問題。比如,哪些是核心抽象組件?它們之間是如何進行交互的?

在這篇文章里,我將會介紹我所發現的一個探索性的設計原則,它或許在某種程度上可以回答上述的問題:

為了可測性而優化代碼

具體地說,就是在你準備寫新代碼時,你要先做好設計,要考慮它們與系統其它組件之間的關系。此時,你要問自己一些問題:“我將如何測試這些代碼?我將如何在盡量不考慮運行環境因素的前提下編寫自動測試用例來驗證代碼的正確性?”如果你無法回答好這些問題,那么請重新設計你的組件或接口。

我將從兩個方面來討論這個原則的好處。

你會得到良好的測試

這個好處或許是顯而易見的:如果你希望讓你的代碼得到良好的測試,那么到最后一般都會如愿。

不過,我認為還有更多的東西值得一說。

首先,我要強調代碼測試的重要性。測試讓檢驗代碼變更的過程變得很簡單:只要運行測試就可以了。沒必要再搭建一個復雜的開發環境,也沒必要與系統進行各種復雜的交互,只要敲入簡單的make test命令,然后等待結果。這樣最起碼可以知道你的代碼變更是否按照你所期待的那樣運行,并且知道它們是否對重要功能造成破壞。

在成熟的大型軟件系統里,在做出變更時最困難的部分不是變更本身,而是如何保證所做的變更不會對系統的重要功能造成影響。好的測試可以為此提供最基本的保障,因此測試是一種富有生產力的改進措施。

其次,為了讓測試所帶來的好處得以體現,你需要運行測試,最起碼要運行那些能夠覆蓋代碼變更的測試用例,而且要盡快運行,以便保證開發的速度。

為了讓這種特性成為一種系統標準,需要有良好的單元測試。人們對“單元測試”、“功能測試”、“集成測試”和其它各種測試之間的邊界的認識極為混亂。在這里,我所說的“單元測試”是指如何使用一些特定的模塊或組件,這些模塊或組件具有較少的對其它組件的依賴或對其它代碼的調用。

有時候你也需要集成測試,集成測試以端到端的方式使用應用程序,以便發現組件間交互的微妙細節。不過,單元測試能夠給我們帶來更多的好處:

  • 單元測試速度很快:使用一小部分代碼就可以運行單元測試,比起要調用整個應用程序,這個要快得多。
  • 更重要的是,單元測試可以伸縮:對于具有大量單元測試的項目來說,測試速度能夠隨著應用的規模線性伸縮。而如果使用大量的端到端測試,你會遇到伸縮問題,因為每個組件的測試會反過來依賴其它組件。
  • 因為單元測試是跟具體的代碼塊相關,所以只針對變更代碼進行測試會變得很容易,這樣可以為開發迭代提供快速的反饋。

好的單元測試并非可遇不可求。如果沒有好的邏輯“單元”就沒有好的單元測試:那些包含小粒度且良好定義的接口的代碼很容易進行單元測試。

這些邏輯單元是良好測試的基礎,而測試反過來為項目提供了快速的反饋。而要找出這些邏輯單元,只要在寫代碼時記住這個準則。

你會得到更好的代碼

在寫代碼時要時刻想著如何測試代碼會帶來更好的代碼!易于測試的代碼有幾個特點:

基于不可變數據的純函數代碼

基于不可變數據結構的純函數代碼非常易于測試:你只需要指定一些成雙的輸入和輸出。通過像QuickCheck這樣的工具可以很容易地進行模糊測試,因為輸入一般都很容易描述。

包含良好定義的接口的小模塊

如果代碼包含了小型的、良好定義的接口,我們可以為它編寫黑盒測試來測試接口的契約,而無需關心模塊內部的細節或系統的其它部分。

IO和計算的分離

一般來說,IO比一般的代碼要難于測試。因此,對于可測試的系統來說,需要把IO從代碼邏輯里分離出來,進行單獨的測試。

顯式聲明的依賴

把數據庫名字隱藏在內部的代碼要比把數據庫名字作為參數傳入的代碼來得更難于測試。對于后者來說,你可以使用不同的參數,每次測試都可以使用不同的新數據庫,或者一次使用多個線程,總之可以根據你的需要來進行測試。

可測試代碼的依賴一般是顯式且參數化了的,而不是隱式且不可變的。

我發現具有良好結構的代碼也有這些特點!當我們以測試為輔來架構一個系統,最后一般都會得到一個更好的系統。

更進一步說,通過測試可以間接地獲得這些結果,我們可以讓它們變為現實。對于一個軟件系統來說,什么樣才算是正確的模塊、接口和結構,這個問題或許沒有定論。但在面對“如何讓代碼變得更易于測試”這個問題時,我們就可以相對容易地做出選擇。

結論

對于一個復雜的軟件系統來說,沒有什么比穩定地發生變更來得更重要,而高質量的自動化測試是達成這種目標最重要的工具之一。好的測試不是可遇不可求的,也不是靠蠻力能夠獲得的:它們是通過設計得來的,因為應用程序賦予了它們這種可能性。

當你在開發軟件時,時常問自己“我將如何測試軟件的準確性”,并且愿意為了達成這個目標對軟件進行良好的設計。作為回報,你將得到一個具有良好結構的系統,你也會因此倍感自信。

 

 

來自:http://www.infoq.com/cn/articles/design-for-testability

 

 本文由用戶 vr862410 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!