本書内容關于如何有效處理遺留代碼,遺留代碼是指沒有編寫測試的代碼。是以,為遺留代碼編寫測試是改善遺留代碼的首要任務。對一個大系統,不可能從頭開始編寫每一處的單元測試,一般隻能從目前需要改動的地方開始,逐漸添加單元測試,形成“軟體夾鉗”,進而修改并改善現有代碼。遺留代碼修改算法:
(1) 确定改動點;(前提:了解代碼)
(2) 找出測試點;(前提:理清代碼間的聯系)
(3) 解依賴;(解依賴是為類編寫單元測試的前提 )
(4) 編寫測試; (編寫符合代碼目前行為的特征測試 )
(5) 修改、重構。 (在存在測試覆寫的前提下,修正bug 、改善設計等 )
從上述算法可以看出,前4 條是關于如何編寫測試代碼的,而解依賴是編寫測試的前提,因為本書很大程度可以說成是關于如何解依賴的書籍,書中也用來很大的篇幅來介紹解依賴技術。當然,解依賴除了處理遺留代碼,還可用于指導編寫易測試的代碼。
測試代碼的命名約定:(測試類:DBEngine )
單元測試類:一個類至少要編寫一個相應的單元測試類,故單元測試類常常在目标類名上加 “Test”字首或字尾。為便于浏覽,加字尾友善些。DBEngineTest
僞類(僞對象或仿對象):僞類是指用于測試的僞造類。 僞類常用”Fake” 作為字首,使得所有的僞類都在一起,便于差別。FakeDBEngine
測試子類(testing subclass ): 測試子類是指利用繼承将不關心的行為架空使隻通路測試所關心的行為的派生子類。 測試子類常由子類化并重寫方法技術生産。測試子類本質就是為測試類接觸不必要的測試依賴。測試子類常使用“Testing ”字首。TestingDBEngine
遺留代碼工作的三個關鍵概念:感覺、分離和接縫 。
感覺和分析和解依賴直接相關,解依賴是将類放入測試用具的重要手段( 有時是唯一手段) ,因為類之間往往是互相依賴,互相影響的,為了能單獨測試某類,我們需要接觸類之間的依賴關系,尤其是測試類所依賴的類。很多時候解依賴唯一的辦法就是通過僞裝成被影響的類來直接感覺所受到的影響。感覺和分離式解依賴的兩個目的:1) 感覺;當無法感覺代碼的狀态 ( 測試) 時,通過解依賴來感覺“狀态”;2) 分離:當無法将代碼放入測試用具時,通過解依賴來分離測試代碼。
類難于測試的根本原因在于:類很少是單獨存在的,往往是互相依賴。所要測試的類往往存在如下依賴關系:1) 執行個體對象(成員變量); 2) 委托對象(接口參數); 3) 臨時對象(所建立或執行個體化的任何對象); 4) 全局對象(單體,系統或庫API )。
注:上述對象不包括基本類型和基本對象(如STL 等标準庫)。
所有的對象都存在自己的邏輯,進而如果想要編寫單獨的類測試用例就應該接觸對這些對象的依賴。下面一一給出解決方案。
1) 執行個體對象(成員變量):使用僞對象
2) 委托對象(接口參數):使用僞對象
3) 臨時對象(所建立或執行個體化的任何對象):使用僞對象
4) 全局對象(單體,系統或庫API ) :以擷取方法替換全局引用;封裝API ,形成内部調用接口,通過子類化并重寫方法,屏蔽不必要的系統API 調用。
使用僞對象的解依賴技術:
參數化構造函數:直接傳入僞對象。
參數化方法:避免臨時對象的寫死,直接傳入僞對象
引入執行個體委托:避免全局對象的寫死,直接傳入僞對象
替換執行個體變量:增加執行個體變量設定接口,不推薦。
引入靜态設定方法:用于替換靜态對象, 如單體執行個體。
參數适配:将依賴的參數類型替換成可僞裝的自定義類型。
實作提取:用于提取抽象基類或接口 ,進而定義僞對象Fake
接口提取:用于提取抽象基類或接口,進而定義僞對象
接觸類内部依賴的解依賴技術:
子類化并重寫方法 :将少數無須測試的内部接口重寫,通過執行個體化重寫的派生類來測試原有類的接口。這裡的重寫是指虛函數的重實作,而非覆寫。
提取并重寫調用:封裝API ,并重寫該接口
提取并重寫工廠方法:用于執行個體化僞對象,避免更改接口,本質就是替換執行個體變量。
提取并重寫擷取方法:延遲擷取執行個體變量,用于C++ 。因為C++ 在構造函數中虛函數機制被禁止,故無法再構造函數中調用子類重寫的工廠方法。
特定情況下的解依賴技術:
分解出方法對象:重構巨型方法
樸素化參數:避免參數依賴
封裝全局引用:
以擷取方法替換全局引用:利于重寫擷取方法。
定義補全:C/C++ 的定義和實作是分開的,通過重寫實作替換原有行為。
連接配接替換:利用連結期接縫,替換庫,DLL 等,實作行為替換。
暴露靜态方法:避免對象的執行個體化,用于難執行個體化的對象。
換函數為函數指針:用于C 的行為替換,不推薦。
寫于2008-5月
本文轉自 zhenjing 部落格園部落格,原文連結:http://www.cnblogs.com/zhenjing/archive/2011/04/20/2021792.html ,如需轉載請自行聯系原作者