單元測試如何改良項目代碼的整體結(jié)構(gòu)

字號:

具有良好整體結(jié)構(gòu)的代碼,應(yīng)該符合“低耦合”的特性,形象的說,就是“各家自掃門前雪、不管他人瓦上霜”,每一個函數(shù)、每一個類、每一個模塊,都應(yīng)該只做自己該做的事,不要把應(yīng)該由“其他人”做的事扯進來。具有良好整體結(jié)構(gòu)的代碼就具有“可測性”,否則就不具有“可測性”。
    系統(tǒng)分析和架構(gòu)設(shè)計做得比較好的項目,所實現(xiàn)的代碼一般具有比較好的整體結(jié)構(gòu),應(yīng)該首先在這方面下功夫。另一方面,單元測試是“隔離”的測試,可以說,“隔離”是單元測試的最基本特性,不能“隔離”的代碼,單元測試也就難于進行。通常,“低耦合”的代碼可以隔離,具有不當(dāng)?shù)母唏詈咸匦缘拇a難于隔離,因此,單元測試能夠及時地發(fā)現(xiàn)不當(dāng)耦合,推動代碼重構(gòu),從而保證了代碼具有良好的整體結(jié)構(gòu)。
    具體來說,如果代碼包含不當(dāng)耦合,當(dāng)這些代碼加入測試工程后,會產(chǎn)生編譯錯誤,或者需要打樁才能測試,從而將不當(dāng)耦合暴露出來。發(fā)現(xiàn)問題后,重構(gòu)代碼、消除不當(dāng)耦合一般不難,消除不當(dāng)耦合后,單元測試就可以順利進行了。
    下面是幾種典型的不當(dāng)耦合:
    把代碼寫在界面類中
    問題:如果把業(yè)務(wù)代碼寫在界面類中,測試時把界面類加入測試工程,會產(chǎn)生編譯錯誤。
    解決:把業(yè)務(wù)代碼獨立出來,寫到相應(yīng)的實體類中,對這些實體類進行測試。界面類只負責(zé)數(shù)據(jù)的顯示和接受用戶的輸入,具體的計算由實體類負責(zé)。
    說明:把業(yè)務(wù)代碼寫在界面類中,這些代碼將很難管理和維護,復(fù)用就更談不上了,這是一定要避免的。采集者退散
    實體類混合了邊界代碼
    問題:例如,一個表示用戶的類CUser,它的對象的數(shù)據(jù)保存在數(shù)據(jù)庫中,如果在CUser類中直接讀寫數(shù)據(jù)庫,就是實體類混合了邊界代碼,這也是一種不當(dāng)耦合,測試CUser類時要察看數(shù)據(jù)庫,或者要打樁,甚至?xí)a(chǎn)生編譯錯誤。
    解決:把執(zhí)行數(shù)據(jù)庫操作的代碼寫到CDatabase類中,CUser類和CDatabase類沒有任何關(guān)聯(lián),由界面類或用于協(xié)調(diào)各對象工作的控制類來操作這兩個類的對象進行數(shù)據(jù)讀寫,現(xiàn)在對CUser類的測試就完全和數(shù)據(jù)庫無關(guān)了。
    說明:經(jīng)過重構(gòu)后,代碼的可擴展性、可復(fù)用性都有了很大提高,也便于進行單元測試和將來的維護??荚嚧笳搲?BR>    無意中形成了高耦合
    問題:例如,CMyClass類中一個函數(shù)中有這樣的語句:
    CDemoApp* pApp = (CDemoApp*)AfxGetApp();
    UNIT var = pApp->GetXXX()->Getxxxx();
    由于CDemoApp是工程的層類,可能跟工程中的所有類關(guān)聯(lián),這兩行代碼就造成被測試對象跟工程中的所有類耦合。耦合具有擴散性,縱向來說,CMyClass類的所有子類也可能跟工程中的所有類關(guān)聯(lián),橫向來說,所有使用了CMyClass類的類,也可能跟工程中的所有類關(guān)聯(lián),從而形成了盤根錯節(jié)的關(guān)系。這種問題往往很難發(fā)現(xiàn),但把代碼加入測試工程后,一般來說是通不過編譯的,從而使問題暴露。來源:考試大
    解決:修改被測試代碼,去除耦合。把需要從pApp指針中取得的數(shù)據(jù)改為由參數(shù)傳進來,這兩行代碼移到客戶程序(即調(diào)用被測試函數(shù)的代碼)中,如果客戶程序也是實體類,則繼續(xù)往上移,直到界面類。
    說明:這類無意中形成的耦合非常常見,一般的代碼審查、靜態(tài)掃描都很難發(fā)現(xiàn)這類問題,但把代碼加入測試工程后,編譯器卻能輕松發(fā)現(xiàn)。這類問題只要及時發(fā)現(xiàn)了,消除并不難,經(jīng)過簡單的代碼重構(gòu)后,就可以有效地提高代碼質(zhì)量,特別是提高代碼的可復(fù)用性,也使單元測試可以順利進行。
    開發(fā)工具生成的代碼形成了不當(dāng)耦合
    有時候,開發(fā)工具生成的代碼也形成了不當(dāng)耦合,例如,VC6.0生成的類代碼中,源文件會添加下面的代碼:#include "ProjectName.h" //ProjectName是工程名
    如果在另一個不同名的工程中復(fù)用代碼,這一行就會產(chǎn)生編譯錯誤。進行單元測試時,這一行形成的不當(dāng)耦合也可能會導(dǎo)致編譯錯誤,因此應(yīng)刪除它。