姚幽然
(1.中國電子科技集團第三十研究所,四川 成都 610041;2.成都國信安信息產業基地有限公司,四川 成都 610041)
軟件并行開發被認為是提高軟件生產效率的最具有潛力的途徑之一。并行開發相對困難,因為團隊成員的工作之間有依賴關系,即軟件組成部分之間的依賴關系[1]。
團隊成員經驗技術、資源占有、接手項目的時間等諸多因素,導致開發進度存在很大差異,而開發模塊之間又存在相互依賴性。例如,程序員A開發的代碼需要依賴程序員B完成的代碼才能進行調試運行,但此時程序員B可能才開始進行需求分析。如何解決以上問題,讓程序員A、程序員B都能按照自己的進度進行開發、調試,打樁或許能夠解決。
實際工作中,存在大量需要快速、有效地對DLL中的代碼進行打樁的情況。本文根據實際需求,提出了如何利用WindowsAPI函數針對DLL進行插樁的技術研究和原理分析,并基于腳本語言建立用例設計與調度的框架。使用腳本技術,大大降低了測試用例編寫的難度,同時提升了效率。
樁,或稱樁代碼,是指用來代替關聯代碼或者未實現代碼的代碼。打樁的目的主要有隔離、補齊和控制。隔離是指將測試任務從產品項目中分離出來,使之能夠獨立編譯、鏈接,并獨立運行。補齊是指用樁來代替未實現的代碼。控制是指人為設定相關代碼的行為,使之符合測試需求。
一個動態鏈接庫封裝了特別復雜的功能,使用者不必關心它是怎樣實現的。當然,這樣也可以使不同的開發者同時開發產品,提高軟件開發的速度。具體流程圖如圖1所示。

圖1 插樁流程圖
1.2.1 修改內存配置
本方案需要修改內存空間的數據,因此在測試初期需要修改系統的配置,將內存保護模式修改為可寫。
為了使插樁盡可能小地影響系統原貌,在修改前需要先將內存配置信息保存,待測試完畢,用例清理現場時再將內存配置恢復。該配置工作將放置于用例初始化階段完成。
1.2.2 利用WindowsAPI獲取函數地址
本方案中主要利用以下三個API函數。
(1)LoadLibrary[2]函數
LoadLibrary函數主要用于加載動態鏈接庫到內存空間,原型為:
HINSTANCE LoadLibrary(LPCTSTR lpLibFileName)
(2)GetProcAddress函數
GetProcAddress函數返回動態鏈接庫中函數的入口地址,原型為:

(3)FreeLibrary函數
FreeLibrary函數主要用于從內存中移除已加載的動態鏈接庫,原型為:

1.2.3 函數插樁原理
使用API函數獲取被測函數地址后,先將被測函數入口處的內容保存,以備恢復時使用。然后,將其替換為一條Jmp指令,使其能跳轉到用戶自定義的測試函數進行執行。Jmp后跟偏移地址,即被測函數入口到測試函數入口的偏移地址:

為保持原程序的健壯性,測試函數執行完畢后,需要恢復被測函數入口處的代碼,并從被測函數返回。
1.2.4 資源回收
用例執行完畢后,需使用FreeLibrary函數將已加載的DLL卸載,否則會引起內存泄露。
清理工作將放置于用例的清理環境階段,同時內存的配置恢復工作也將放置于此階段進行,第2章節會有詳細講解。
前面介紹了插樁的原理,開發人員基本能夠使用它進行簡單的調試工作,但使用起來并不方便。用戶必須要有高級語言的基礎,對使用者的能力也有一定的要求,且所有的測試用例都是孤立的,只能單個運行,無法實現復雜流程的驗證和自動化運行。
針對以上問題,本文提出可使用當前主流、易學、易用的腳本語言將用例層進行封裝。用戶直接使用腳本語言便可進行腳本的編寫、調試,大大降低了難度。同時,增加用例集的概念,可實現自動化測試。
系統運行時序圖如圖2所示。

圖2 系統運行時序圖
2.2.1 獲取DLL函數信息
本方案底層以VS為例進行介紹。初始階段,用戶利用接口從VS端獲取DLL的函數列表,根據界面呈現的函數列表進行腳本開發,被測函數的選取范圍即為返回的函數列表。
用例的格式可自定義,也可直接使用系統的標準格式,詳見測試床的介紹。
2.2.2 封裝測試床
定義AW(ActionWord),封裝測試床,快速構建腳本框架:

Initial函數內容可包括對測試環境的初始化、對被測對象的測試準備等工作。對內存空間的配置,可放置在初始化階段執行。
Action函數為用例的主要內容,包含被測函數的調用等,可以有多個。
CheckPoint為檢查點函數,主要包括對用例執行情況的檢查,可以有多個,通常與Action配套使用。
一個用例中所有的檢查點都通過,此用例的結果為通過;否則,不通過。測試結果將所有檢查點的執行情況都列出,以供用戶定位問題。
Finish函數內容包括清理測試環境、恢復內存配置等工作。
以上函數內容、執行順序均由用戶自定義。模板可提供統一的格式供用戶快速開發。
2.2.3 腳本的自動化調度運行
用戶界面提供測試集的概念,用戶可針對不同的對象任務創建測試集,制定執行計劃。根據筆者經驗,通常用戶可將測試任務啟動時間設置在晚上。此時,測試環境通常較為空閑,不會影響開發的調試工作。
2.2.4 上層與底層交互
上層腳本逐條經接口層處理后發到VS端執行,執行結果經原路返回腳本端保存,并展示給用戶。
本文闡述了基于WindowsAPI函數進行插樁的原理,方便簡單、靈活、易于實現。另外,上層使用腳本進行封裝,將用戶與底層高級語言隔離,降低了用例開發的難度;上層腳本語言選擇的范圍非常廣泛,開發者可根據實際情況選擇適合的腳本語言進行封裝,非常靈活,有助于實現快速迭代開發、并行測試等應用場景。
[1] 黃柳青,溫昱.面向構件的軟件過程:并行開發與測試[J].中國金融電腦,2007(09):61.HUANG Liu-qing,WEN Yu.Component-oriented Software Process:Parallel Development and Testing[J].Financial Computer of China,2007(09):61.
[2] 張錚,孫寶山,周天立.Windows程序設計[M].第3版.北京:人民郵電出版社,2015.ZHANG zheng,SUN Baoshan, ZhOU Tian-Li.Windows programming[M].Third Edition.BeiJing: People's post and Telecommunications Press,2015.