簡介:AOP 使編寫特定于應(yīng)用程序的橫切關(guān)注點測試比任何時候都要容易了 。 要了解其原因以及如何實現(xiàn),請聽 Nicholas Lesiecki 介紹測試面向方面的代 碼 所具有的好處,并展示在 AspectJ 中測試橫切行為的樣式。
在過去五年中廣泛采用的程序員測試是由顯著的生產(chǎn)率和得到的代碼質(zhì)量所 驅(qū) 動的。不過,在面向方面編程(AOP)出現(xiàn)之前,為橫切行為(如安全、事務(wù)管 理 或者持久性)編寫測試很困難。為什么呢?因為這些行為沒有很好地模塊化。如 果沒有可測試的單元,那么很難編寫出單元測試。隨著 AOP 的普及,編寫與 橫 切關(guān)注點在目標(biāo)系統(tǒng)中的實現(xiàn)無關(guān)的、對其進(jìn)行檢查的測試已變得可行并且值得 去做。
在本文中,我將介紹測試用方面實現(xiàn)的橫切行為的一組技術(shù)。重點放在方面 的 單元測試,但是我也展示了有助于建立對面向方面應(yīng)用程序的信任度的其他模式 。很快您會看到,測試方面涉及許多與測試對象相同的技巧和概念,并且有許 多相同的做法和設(shè)計好處。
本文的撰寫基于我在 AspectJ 中的經(jīng)驗。許多概念應(yīng)當(dāng)可以移植到其他 AOP 實現(xiàn)中,但是有些概念是特定于語言的。請參閱 下載 以下載本文源代碼,請參 閱 參考資料 以下載完成例子所需要的 Aspectj 和 AJDT。
面向方面代碼的單元測試
應(yīng)用程序的好的自動測試集應(yīng)當(dāng)像圖 1 那樣:以隔離的、對各個類的測試構(gòu) 成一個廣泛的基礎(chǔ),使測試覆蓋面廣,并能迅速分離出錯誤。在這之上是集成的 、端到端的系統(tǒng)測試,它驗證各單元是否可以協(xié)調(diào)工作。如果這些層是良構(gòu)的并 且頻繁運(yùn)行,那么它們結(jié)合在一起可以增加對于應(yīng)用程序行為的信任度。
在金字塔底部的單元測試很重要,這有幾個理由。首先,它們幫助您產(chǎn)生那 些 在集成測試中難于再現(xiàn)或者需要繁瑣步驟才能再現(xiàn)的關(guān)注點用例。其次,由于它 們涉及的代碼更少,因此它們運(yùn)行起來通常更快(因此可以更經(jīng)常地運(yùn)行它們) 。第三,它們可以幫助您思考每個單元的接口和要求。好的單元測試要求單元間 的松散耦合,這是在測試條件下讓測試得以運(yùn)行的條件。
圖 1. 分層的測試
但是橫切行為會怎么樣呢?想像一位客戶的要求:“在執(zhí)行對 ATM 類的任何 操作之前要檢查調(diào)用者的安全憑證。”當(dāng)然可以(并且應(yīng)該)針對這項要求編寫 集成測試。不過,非面向?qū)ο蟮拈_發(fā)環(huán)境使得編寫“在操作之前檢查安全性”這 種行為的單元測試很難將這種行為分離出來。這是因為行為混入到了目標(biāo)系統(tǒng)中 ,讓人很難把握或者用工具分析。但是如果用方面開發(fā),那么可以將這些行為 表示為建議(advice),應(yīng)用到所有匹配某個切點(pointcut)的操作。現(xiàn)在行 為可以很好地用單元表示,可以在隔離的情況下測試或者在 IDE 顯示它。
面向方面的代碼在哪里出現(xiàn)問題了
在討論對方面進(jìn)行單元測試的技術(shù)之前,我要簡單討論錯誤類型。橫切行為 分 為兩個主要部分:行為做什么(我稱之為橫切功能)和行為用在什么地方(我稱 之為橫切規(guī)范);氐 ATM 的例子,橫切功能檢查調(diào)用者的安全憑證。橫切規(guī) 范 檢查 ATM 類中每一個公共方法。
為了實現(xiàn)的真正信任度,需要同時檢查功能和規(guī)范(或者不嚴(yán)格地說,建議 和 切點)。在完成這個例子的過程中,我將強(qiáng)調(diào)給定的測試模式是驗證橫切功能、 規(guī)范,還是兩者同時驗證。
注意我將重點放在測試切點、建議和支持它們的代碼上。類型間聲明(和其 他 方面功能)當(dāng)然是可測試的。我在本文中展示的一些技巧稍加修改可以對它們 使用。它們還有自己的一組技巧,其中許多是很直觀的。不過為了節(jié)省篇幅,我 決定不在本文中明確地討論它們。
測試模式編目
我將本文寫成測試面向方面代碼的模式的編目。對于每種模式,我描述了它 針 對哪種類型的錯誤,對該模式進(jìn)行總結(jié),提供一個例子并討論該模式的優(yōu)缺點。 編目分為四節(jié):
測試完整的單元 :此節(jié)展示了測試完整的系統(tǒng)部分(換句話說,同時測試方 面和非方面類)的模式。這種技術(shù)是在沒有使用方面時獲得橫切行為信任度的惟 一方法,并在使用方面時仍然是一種重要的工具。
使用可視化工具 :這里描述的兩種模式利用了 AspectJ IDE 對 Eclipse 的 支持,也稱為 AJDT。嚴(yán)格地講,使用可視化工具檢查應(yīng)用程序的橫切結(jié)構(gòu)不是 一 種測試技術(shù)。不過,它可幫助您理解并獲得對應(yīng)用程序的橫切關(guān)注點的信任。
使用委派 :此節(jié)展示可以幫助將前面提到的兩類錯誤分開的兩種模式。通過 將一些邏輯從建議中分離到 helper 類中(或者方法中),可以編寫與橫切規(guī)范 無關(guān)的、檢查應(yīng)用程序橫切行為的測試。
使用 mock 目標(biāo) :后一節(jié)包括三種模式,它們使用模擬真實建議目標(biāo)的 “mock 目標(biāo)”類,可以在不將方面集成到真正目標(biāo)的條件下測試聯(lián)結(jié)點匹配和 建 議行為。
Highlighter 方面
為了展示這個編目中的樣式,我使用了一個實現(xiàn)突出顯示搜索術(shù)語(即在搜 索 結(jié)果中突出顯示用戶的查詢術(shù)語)的方面。我實現(xiàn)了與在上一例子中展示的方面 非常相像的一個方面。該系統(tǒng)要在結(jié)果匯總頁、細(xì)節(jié)頁和應(yīng)用程序的其他一些地 方中突出顯示術(shù)語。我在本文中展示的這個例子只橫切一個類,但是原理是一樣 的。清單 1 包含 Highlighter 方面的一個實現(xiàn):
清單 1. Highlighter 定義了突出顯示行為
public aspect Highlighter{
/* ITDs to manage highlighted words */
private Collection Highlightable.highlightedWords;
public Collection Highlightable.getHighlightedWords() {
return highlightedWords;
}
public void Highlightable.setHighlightedWords(Collection
highlightedWords){
this.highlightedWords = highlightedWords;
}
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 = patternForWord(word);
Matcher matcher = pattern.matcher (highlighted);
highlighted = matcher.replaceAll(" "bold">$0");
}
return highlighted;
}
private Pattern patternForWord (String word) {
return Pattern.compile("\b\Q" + word + "\E\b",
Pattern.CASE_INSENSITIVE);
}
}