過去五年程式設計師測試廣泛普及,但在 AOP 出現前,安全、事務、持久化等橫切行為難以編寫單元測試——因為它們缺乏良好模組化。AOP 將橫切行為模組化為「通知」應用於「切點」匹配的連接點,使得針對橫切功能與規範的隔離測試成為現實。本文介紹八種測試模式,涵蓋整合測試、可視化檢查、委託測試與 Mock 目標技術。
真正的信心需同時驗證兩者。本文聚焦切點、通知與支援代碼測試;型別間宣告等特性原理類似,篇幅所限不詳述。
public aspect Highlighter {
private Collection<String> Highlightable.highlightedWords; // ITD
public pointcut highlightedTextProperties() :
execution(public String getProduct()) || execution(public String getTitle()) || execution(public String getSummary());
String around(Highlightable highlightable) : highlightedTextProperties() && this(highlightable) {
String highlighted = proceed(highlightable);
for (String word : highlightable.getHighlightedWords()) {
Pattern pattern = Pattern.compile("\\b\\Q" + word + "\\E\\b", Pattern.CASE_INSENSITIVE);
highlighted = pattern.matcher(highlighted).replaceAll("<span class=\"bold\">$0</span>");
}
return highlighted;
}
}
如同無 AOP 時編寫測試:組裝物件、設定狀態、呼叫方法、驗證結果。
public class HighlightSearchResultsIntegrationTest extends TestCase {
public void testHighlighting() {
SearchResult result = new SearchResult();
result.setTitle("I am a big bear!");
result.setHighlightedWords(Arrays.asList("big", "grrr"));
assertEquals("I am a <span class=\"bold\">big</span> bear!", result.getTitle());
}
}
優點:驗證高層目標、支援大規模重構、發現元件交互問題。
缺點:失敗原因難隔離 (通知邏輯? 切點未匹配? 目標類別錯誤?)、設置斷言複雜、難覆蓋邊界情況、跨類別橫切行為測試目的模糊。
開發時使用 AJDT Cross-References 視圖查看切面建議哪些連接點。
範例:將切點改為 execution(public String get*()) && !execution(public * Highlightable.*(..)),視圖顯示多匹配了 getWebsite(),即時發現並修正。
優點:即時回饋、易發現難測試的誤匹配、自動驗證大量連接點。
缺點:非自動化、依賴開發者自律、僅顯示靜態連接點陰影 (無法確定 cflow()/if() 執行期匹配)。
重構前後保存專案橫切圖,比較差異。
範例:改用 @Highlighted 註解切點,比較工具顯示 getWebsite() 移除正確,但 getSummary() 也意外移除 (漏加註解)。
優點:聚焦變更、防止資訊盲點、可檢查整個專案。
缺點:影響連接點多的切面 (如日誌所有公共方法) 雜訊大,需配置過濾。
將通知邏輯抽出至獨立類別 (如 HighlightUtil),單元測試工具類方法。
優點:易產生邊界案例、隔離問題來源、獲得更乾淨關注點分離 (可切換 HTML/純文字高亮策略)。
缺點:邏輯難抽取時無效、狀態儲存 (ITD/切面欄位) 不易移至輔助類。
注入 Mock HighlightUtil 驗證通知於正確連接點觸發、傳遞正確上下文。
關鍵點:單例切面欄位變更需在 tearDown() 還原,否則污染後續測試。建議編寫測試清理切面自動化此過程。
Mock 目標:模擬切面合法建議目標的測試輔助類。
基礎範例:HighlightMockTarget implements Highlightable { public String getSomeString() { return "I am a big bear!"; } }
將 Highlighter 拆為 AbstractHighlighter (抽象切點) + HighlightResults (具體切點)。測試類內建立 HighlightsTestClass extends AbstractHighlighter 針對 Mock 目標定義切點。
優點:驗證通知與 ITD 邏輯、測試程式碼清晰 (無需閱讀真實目標行為)、適合庫切面測試 (真實目標尚不存在)、促使切面解耦更易擴展。
改寫切點匹配介面方法 (如 execution(public String Highlightable+.get*())),Mock 目標實作介面即自動匹配。或使用註解切點,Mock 目標加註解。
優點:強迫切點寬鬆耦合、保證真實類別易參與、測試更獨立。
模擬控制流:MockGenerator 呼叫 HighlightMockTarget,驗證 cflow(ReportGenerator) 排除高亮。
價值:可視化工具無法分析執行期切點 (cflow、cflowbelow),Mock 目標提供實際驗證。
測試切面如測試物件,核心在於將行為分解為可獨立測試的組件。關鍵洞見:橫切關注點分為「規範」與「功能」兩個維度,AOP 使它們可分別或同時針對性驗證。編寫可測試切面帶來的設計紅利 (邏輯抽取、切點鬆耦合) 與重構 OO 代碼獲致可測試性的益處異曲同工。AOP 不僅可測試,更讓橫切關注點測試變得更好。完整源碼請至 IBM developerWorks 下載。