單元測試

在計算機程式設計中，單元測試中的方法。通常來說，程式設計師每修改一次程式就會進行最少一次單元測試，在編寫程式的過程中前後很可能要進行多次單元測試，以證實程式達到軟體規格書要求的工作目標，沒有程式錯誤；雖然單元測試不是必須的，但也不壞，這牽涉到專案管理的政策決定。每個理想的測試案例獨立於其它案例；為測試時隔離模組，經常使用stubs、mock或fake等測試馬甲程式。單元測試通常由軟體開發人員編寫，用於確保他們所寫的程式碼符合軟體需求和遵循開發目標。它的實施方式可以是非常手動的，或者是做成構建自動化的一部分。收益.單元測試的目標是隔離程式部件並證明這些單個部件是正確的。一個單元測試提供了程式碼片斷需要滿足的嚴密的書面規約。因此，單元測試帶來了一些益處。單元測試在軟體開發過程的早期就能發現問題。適應變更.單元測試允許程式設計師在未來重構程式碼，並且確保模組依然工作正確。這個過程就是為所有函式和方法編寫單元測試，一旦變更導致錯誤發生，藉助於單元測試可以快速定位並修復錯誤。可讀性強的單元測試可以使程式設計師方便地檢查程式碼片斷是否依然正常工作。良好設計的單元測試案例覆蓋程式單元分支和迴圈條件的所有路徑。在連續的單元測試環境，透過其固有的持續維護工作，單元測試可以延續用於準確反映當任何變更發生時可執行程式和程式碼的表現。藉助於上述開發實踐和單元測試的覆蓋，可以分分秒秒維持準確性。簡化整合.單元測試消除程式單元的不可靠，採用自底向上的測試路徑。透過先測試程式部件再測試部件組裝，使整合測試變得更加簡單。業界對於人工整合測試的必要性存在較大爭議。儘管精心設計的單元測試體系看上去實現了整合測試，因為整合測試需要人為評估一些人為因素才能證實的方面，單元測試替代整合測試不可信。一些人認為在足夠的自動化測試系統的條件下，人力整合測試組不再是必需的。事實上，真實的需求最終取決於開發產品的特點和使用目標。另外，人工或手動測試很大程度上依賴於組織的可用資源。文件記錄.單元測試提供了系統的一種文件記錄。藉助於檢視單元測試提供的功能和單元測試中如何使用程式單元，開發人員可以直觀的理解程式單元的基礎API。單元測試具體表現了程式單元成功的關鍵特點。這些特點可以指出正確使用和非正確使用程式單元，也能指出需要捕獲的程式單元的負面表現。儘管很多軟體開發環境不僅依賴於程式碼做為產品文件，在單元測試中和單元測試本身確實文件化了程式單元的上述關鍵特點。另一方面，傳統文件易受程式本身實現的影響，並且時效性難以保證。表達設計.在測試驅動開發的軟體實踐中，單元測試可以取代正式的設計。每一個單元測試案例均可以視為一項類、方法和待觀察行為等設計元素。下面的Java例可以幫助說明這一點。這是一個證明一批實現設計元素的測試類。首先，要求有一個名為Adder的介面，和一個不帶引數的構造方法名為AdderImpl的實現類。然後，它斷言Adder介面包含有一個兩個整數引數返回值為整型的add方法。它也透過小範圍的值檢驗說明方法的行為。public class TestAdder {public void testSum() {Adder adder = new AdderImpl();assert(adder.add(1, 1) == 2);assert(adder.add(1, 2) == 3);assert(adder.add(2, 2) == 4);assert(adder.add(0, 0) == 0);assert(adder.add(-1, -2) == -3);assert(adder.add(-1, 1) == 0);assert(adder.add(1234, 988) == 2222);這個案例中，單元測試在程式之前寫成，用作指明待設計的物件形態和行為的文件，沒有任何實現細節，留作程式設計師練習。以下可能是最簡單的工作實踐，這個最容易的解決方案可以透過上述測試：interface Adder {int add(int a, int b);class AdderImpl implements Adder {int add(int a, int b) {return a + b;不同於其他基於圖的設計方法，用單元測試表達設計有一項顯著優點：設計文件可以用於驗證程式實現符合設計。UML可能會遇到這樣的問題：儘管圖上一個類被命名為Customer，但開發人員可以稱其為Wibble，而且系統中沒有任何地方會顯示出這個差異。基於單元測試設計方法，開發人員不遵循設計要求的解決方案永遠不會透過測試。當然，單元測試缺乏圖的可讀性，但UML圖可以在自由工具中為大多數現代程式語言生成UML圖，很難要求採購昂貴的UML設計套裝軟體。自由工具，類似於基於xUnit框架的工具，測試結果輸出到一些可生成供人工識讀的圖形化工具系統中去。分離介面和實現.因為很多類會引用其它類，對這個類的測試經常會要求測試其它的類。一個最普遍的例子是依賴於資料庫的類：為了測試它，測試人員通常編寫程式碼去操作資料庫。這是不對的，因為單元測試不應超出待測試的類邊界。作為替代，軟體開發人員應建立一個數據庫連線的抽象介面，然後實現這個介面的模擬物件。透過對程式碼所需附件的抽象，這些獨立程式單元較前者更能被完整測試。高質量的程式碼單元也可提供更好的可維護性。侷限.測試不可能發現所有的程式錯誤，單元測試也不例外。按定義，單元測試只測試程式單元自身的功能。因此，它不能發現整合錯誤、效能問題、或者其他系統級別的問題。單元測試結合其他軟體測試活動更為有效。與其它形式的軟體測試類似，單元測試只能表明測到的問題，不能表明不存在未測試到的錯誤。軟體測試是一個組合問題。例如，每一個布林型的決斷語句需要至少兩種測試：一個返回真，一個返回假。因此，針對每行書寫的程式碼，程式設計師通常需要寫3至5行的測試程式碼。這很明顯地很花時間而且對此的投入可能並不值得。也有些問題是根本不能簡單地檢測出來的——例如具不確定性的或牽扯到多執行緒的問題。此外，替單元測試寫的程式碼可能就像要測試的程式碼一樣有程式錯誤。佛瑞德·布魯克斯在人月神話一書中舉例說明：「絕對不要帶兩個計時器去海邊。最好總是帶一或三個」。意味著，如果兩個計時器互相衝突的話，你該怎麼知道哪個是對的？為了獲得單元測試的好處，在軟體開發過程中應形成一套嚴格紀律意識。仔細保留記錄是必要的，不僅僅只保留執行的測試，也包括保留對應的原始碼和其它軟體單元的變更歷史。即，使用版本控制系統是必要的。如果後續版本不能透過一個以前測試透過的單元測試，版本控制系統可以提供對應時間段對原始碼所做的變更清單。每天養成檢視單元測試案例失敗測試並及時確定錯誤原因的習慣是必要的。如果沒有這樣的流程，沒有在團隊工作流程中體現，單元測試系列將走向不同步，造成越來越多的錯誤和越來越低效的單元測試案例系列。應用.極限程式設計.單元測試是極限程式設計的基礎，依賴於自動化的單元測試框架。自動化的單元測試框架可以第三方，如xUnit，也可以由開發組自己建立。極限程式設計建立單元測試用於測試驅動開發。首先，開發人員編寫單元測試用於展示軟體需求或者軟體缺陷。因為需求尚未實現或者現有程式碼中存在軟體缺陷，這些測試會失敗。然後，開發人員遵循測試要求編寫最簡單的程式碼去滿足它，直到測試得以透過。系統中大多數程式碼都經過單元測試，但並非所有程式碼路徑都必需單元測試。極限程式設計強調“測試所有可能中斷”的策略，而傳統方法是“測試所有執行路徑”。這使得極限程式設計開發人員比傳統開發少寫單元測試，但這並不是問題。不爭的事實是傳統方法很少完全遵循完整地測試所有執行路徑的要求。極限程式設計相互地認識到測試很少能完備，提供瞭如何有效地將有限資源集中投入可花費的代價到問題關鍵的導引。至關重要的，測試程式碼應視為第一個專案成品，與實現程式碼維持同等級別的質量要求，沒有重複。開發人員在提交程式單元程式碼時一併提交單元測試程式碼到程式碼庫。徹底的極限程式設計單元測試程式碼提供上述單元測試的收益，如簡化和更可信的程式開發和重構、簡化程式碼整合、精確的文件和模組化的設計。而且，單元測試經常作為複合測試的一種形式被執行。技術.單元測試通常情況下自動進行，但也可被手動執行。IEEE沒有偏愛某一種形式。手動的單元測試可用於step-by-step的教學文件。儘管如此，單元測試的目標是隔離程式單元並驗證其正確性。自動執行使目標達成更有效，也可獲得本文上述單元測試收益。相反，不細心規劃或者精心的單元測試可能被視為包括多個軟體元件的整合測試案例，於是將因未完全達到建立單元測試的預定目標，測試可能失去較多收益。在自動化測試時，為了實現隔離的效果，測試將脫離待測程式單元本身固有的執行環境之外，即脫離產品環境或其本身被建立和呼叫的上下文環境，而在測試框架中執行。以隔離方式執行有利於充分顯露待測試程式碼與其它程式單元或者產品資料空間的依賴關係。這些依賴關係在單元測試中可以被消除。藉助於自動化測試框架，開發人員可以抓住關鍵進行編碼並透過測試去驗證程式單元的正確性。在測試案例執行期間，框架透過日誌記錄了所有失敗的測試準則。很多測試框架可以自動標記和提交失敗的測試案例總結報告。根據失敗的程度不同，框架可以中止後續測試。總體說來，單元測試會激發程式設計師創造解耦的和內聚的程式碼體。單元測試實踐有利於促進健康的軟體開發習慣。設計模式、單元測試和重構經常一起出現在工作中，藉助於它們，開發人員可以生產出最為完美的解決方案。單元測試框架.單元測試框架通常是沒有作為編譯器套件的第三方產品。他們幫助簡化單元測試的過程，並且已經為各種程式語言開發。通常在沒有特定框架支援下，透過撰寫在測試中的執行單元，並使用判定、異常處理、或其他控制流程機制來表示失敗的使用者程式碼執行單元測試是可行的。不透過框架的單元測試有用之處在於進行單元測試時會有一個；進行一點單元測試幾乎不比沒做好多少，但是一旦使用了框架，加入單元測試相對來說會簡單許多。在某些框架中許多先進單元測試特徵遺失了或者必須是手工編寫的。語言層單元測試支援.某些程式語言直接支援單元測試。他們的語法允許直接進行單元測試的宣告而不需要匯入。除此之外，單元測試的布林條件可以用與非單元測試碼的布林表示法相同的語法來表示，例如if和while宣告的用法。直接支援單元測試的語言包含了：