在寫這個自動化測試框架的時候,我一直在留意各方面的需求。畢竟,我本人并沒有做過真正的自動化測試。管理測試方面的領導,提出一個需求,就是在用例運行失敗的時候,應該將過程記錄下來,并形成報告,Email給相關人員。
個人認為這個需求是非常合理的。事實上,任何系統,如果沒有輸出,那么只能停留在程序員手里。有了報表,才叫真正解決了用戶的目標需求。
在分析這個需求的過程,我提出了針對每一個操作接口的每一個方法,進行Log。而完成這個工作的第一方法,就想到了AOP,也就是Hook技術的應用。因為Delphi下面并沒有對AOP的直接支持,所以考慮這個實現,變成了一個技術研究過程。
從技術上講,本篇博客只適合了解VCL的Delphi程序員閱讀。但其間的思想,相信大家都可以借鑒。下面我的描述過程,是以我的探索過程來進行講述的。中間會帶出相關技術點,供大家參考。
第一、接口的方法,是由類來實現的??蚣苤?,已經對所有支持的類都進行了登記。那么,只需要在這些類型中,找到所有實現的接口的所有方法的地址,那么Hook就變得有可能了。
TObject有一個方法:GetInterfaceTable,可以獲取所有接口列表。所有非常容易找到接口對應的VTable。VTable在Delphi中并沒有明確的注釋,但是可以知道VTable是一個指針列表,每一項都記錄著一個方法的“實現地址”。
可惜的是,我發現VTable本身并沒有告訴你,這個接口有多少個方法!另外,你也不能得到每一個方法的名稱,以及參數等等描述。
第二、于是我考慮到接口的RTTI。接口的RTTI,我以前是沒有使用過的。通過VCL的代碼研究,發現接口中有一個非常特殊的接口定義:{$M+}IInvokable = interface;{$M-}。這個接口本身并沒有添加什么服務,只是使用了編譯指令M,來使得接口擁有了RTTI。
實現的時候,可以通過從IInvokable派生,或者直接添加編譯指令,從而獲得RTTI服務。
下面的問題是,如何使用RTTI?我們知道,Delphi中有一個單元叫TypInfo.pas,后來我發現,其實有另外一個單元叫:IntfInfo.pas。這里面有一個方法GetIntfMetaData可以幫助你獲得RTTI。另外,值得一提的是,獲取接口類型的PTypeInfo的方法是調用TypeInfo(IMyInterface);
第三、通過MetaData分析,我們可以知道接口的方法個數以及每一個方法的詳細定義。那么,現在就是如何Hook了。下面是一個Object的對象實例事例圖。
原文轉自:http://www.anti-gravitydesign.com