Q: 怎么測 private 函數?
A: 把它變成 public 的.
我是認真的. 如果發現 private 函數無法簡單的通過某個public函數的測試來覆蓋而需要專門的測試, 意味著你的單元可能承擔了太多的職責, 應該拆分到一個單獨的單元中, 并開放為 public 函數.
如果使用 C++, 在測試環境中 #define private public.
如果使用 g++, 在測試環境中加入 -fno-access-control.
Q: 類似 private, 一些意圖實現良好設計的語言特性, 如 static, sealed, final, 非虛函數等, 卻總是給代碼的易測試性帶來麻煩, 該如何取舍?
A: 沒什么好辦法. 這些語言特性和測試的目的是相同的, 都是為提高代碼質量, 減少出錯的可能, 雖殊途同歸, 但卻互相限制, 效果也不一樣.
我認為工業界是時候嚴肅認真的考慮測試環境了, 最好在語言中內建對測試的支持, 一些為產品環境設計的語言特性, 應該在測試環境中關閉, 而在產品環境中生效. 其實之前很多編譯器都支持 Release 和 Debug 兩種環境, 也是從代碼質量的方面考慮的. 現在毫無疑問證實單元測試比 Debug 更有效, 是時候與時俱進增加對 Test 的支持而逐漸罷黜對 Debug 的支持.
在語言本身增加對測試的支持之前, 我們不得不想辦法在測試環境中繞過語言特性的限制, 尤其對遺留系統, 代碼已經存在的情況. 比如對于 C++ 中的 static 函數, 可以將整個被測單元 #include, 或者 #define static 為空. 宏代表了一層間接, 在測試環境中, 這層間接是至關重要的. 其它方法可參考 <<Working Effectively with Legacy Code>>, <<假冒的藝術>>中的介紹.
Q: 剛才提到了要支持"測試"而不是"Debug", 測試和Debug難道有什么矛盾嗎?
A: 有. 如果你發現不得不 Debug, 就是測試粒度太粗, 步子邁的太大, 產品代碼過長等導致的, 甚至可能你卷入了過多的單元而破壞了測試的隔離性. Debug還是代碼邏輯不清, 行為難以斷言的表現. 用測試幫你定位錯誤.
Q: 我知道為遺留系統增加新特性是要先寫測試保證系統原來的行為, 可遺留代碼很龐大, 我甚至都不知道系統目前的行為, 怎么辦?
A: 特征測試: 保持代碼行為的測試, 獲取當前運行結果, 來填充測試, 以獲取系統目前行為. 其實測試可以分為兩類: 試圖說明想要實現的目標, 或者試圖保持代碼中既有的行為; 在特性實現后, 前者會轉化為后者. 詳細信息請參見<<Working Effectively with Legacy Code>>
Q: 前面經常說到 C++ 或其它面向對象語言, 卻沒有提到 C, 那么過程式語言中如何應用 TDD ? 有什么不一樣?
A: 基本一樣, 并且在過程式語言中應用 TDD, 可能會導出面向對象風格的設計. 比如如果直接調用某個函數, 那么不得不通過編譯時替換或鏈接時替換來接入假的實現. 這樣其實比較麻煩, 因此可能會促使你選用函數指針 ,以便方便的在測試環境中進行替換. 隨著時間的推移, 你會發現一組組概念相關的函數指針出現了, 那么把它們和它們操作的數據綁定在一起, 定義一個 struct, 就形成了一種對象風格. 當然這反而可能會令你的代碼更復雜, 這需要在實踐中取舍.
也有可能在過程式語言中你覺得 TDD 對設計的促進不大, 而且測試用例也比較枯燥, 就是測個分支, 返回值什么的. 是的, 邏輯就隱藏在分支和返回值中, 如果習慣了過程式思維并不打算改變, TDD 對設計的影響則更多的體現在依賴管理上, 如頭文件和編譯單元的職責劃分. 如果把不同職責的函數混在一個編譯單元里面, 則很難實施鏈接替換等手段, 除非你選擇一個類似 mockcpp 的框架, 不需要鏈接替換.
Q: 如果使用 TDD, 那么測試人員怎么安排? 是不是一開始就要進入項目組? 可那時還沒有產品代碼,測什么?
A: 是, 是一開始就要進入項目組, 可不是因為 TDD. 是, 測試人員是一開始沒什么可測的, 可不代表就沒活干.
TDD是一種開發方法, 是開發人員參與的活動. 其效果是以可執行的形式文檔化你的需求, 迫使你分清職責隔離依賴以驅動你的設計, 編織安全網以扼殺Bug在搖籃狀態防止逃逸. 可傳統測試人員的活動是試圖找到已經逃逸的Bug. 這兩種活動都是必要的, 而且毫不沖突, 互為補充.
那么測試人員在新的特性還沒開發完成之前做什么呢? 除了提前寫測試用例, 無論是自動化的還是非自動化的, 而需要測試人員參加的一項重要活動, 就是參與特性驗收條件的制定. 之前經常發生開發人員按照自己的理解去編碼, 測試人員按照自己的理解去測試, 直到開發完成, 測試過程中才發現理解的不一致, 開始產生爭執并阻塞等待業務分析人員(如果幸運的話)或者行政主管(如果開發過程混亂的話)的仲裁. 解決辦法就是就在開始開發新特性前的一剎那, 由業務分析人員, 測試人員, 開發人員進行一次討論, 就驗收條件達成一致并形成記錄, 然后測試人員和開發人員分頭去寫測試和實現.
文章來源于領測軟件測試網 http://www.kjueaiud.com/