您的位置:軟件測試 > 開源軟件測試 > 開源單元測試工具 >
AOP@Work: 對方面進行單元測試
作者:網(wǎng)絡(luò)轉(zhuǎn)載 發(fā)布時間:[ 2013/3/12 17:03:58 ] 推薦標(biāo)簽:

然后,編寫測試用例以驗證方面正確地與目標(biāo)交互,如清單 4 所示:

清單 4. 與 mock 目標(biāo)交互以測試建議

public void setUp() throws Exception {
super.setUp();
setUpMockHighlightUtil();
words = Collections.singleton("big");
mockTarget = new HighlightMockTarget();
mockTarget.setHighlightedWords(words);
}
//mock setup/tearDown omitted
public void testHighlighting() {
mockUtil.expects(once())
.method("highlight")
.with(eq("I am a big bear!"), eq(words))
.will(returnValue("highlighted text"));
String shouldBeHighlighted = mockTarget.getSomeString();
assertEquals(shouldBeHighlighted, "highlighted text");
}

注意在這個例子中,我結(jié)合了 mock 目標(biāo)和 mock 對象(如在 第 III 節(jié), 模式 2 中所描述的)。mock 目標(biāo)為下面三種技術(shù)提供了基礎(chǔ)。

模式 1. 通過擴展一個抽象方面并提供一個切點來測試建議

針對 :橫切功能

概述 :Prework :如果有必要,重新編寫方面,將它分為一個抽象方面以及 一個擴展它并具體化一個或者多個切點的具體方面。

有了抽象方面后,在測試類中創(chuàng)建一個 mock 目標(biāo)。創(chuàng)建一個擴展了抽象方 面的測試方面。讓測試方面提供明確針對 mock 目標(biāo)的切點。這個測試通過查找 建議的已知副作用或者使用一個 mock 對象來驗證方面中的建議是否成功。

示例:擴展 AbstractHighlighter

假定已經(jīng)編寫了 上一節(jié)中的測試代碼。為了使測試通過,必須將 Highlighter 方面分解為一個抽象方面和一個子方面,如下所示:

public abstract aspect AbstractHighlighter {
public abstract pointcut highlightedTextProperties();
//... aspect continues
}
public aspect HighlightResults extends AbstractHighlighter {
public pointcut highlightedTextProperties() :
(
//...define pointcut as before
);
}

下一步,用一個只用于測試案例的方面擴展 AbstractHighlighter 方面。下 面我將它展示為測試案例的一個靜態(tài)內(nèi)部方面:

private static aspect HighlightsTestClass extends AbstractHighlighter {
public pointcut highlightedTextProperties() :
execution(public String HighlightMockTarget.*(..));
}

這個方面通過選擇 mock 目標(biāo)上所有的方法執(zhí)行具體化了 highlightedTextProperties 切點。

優(yōu)缺點

顯然,這種測試過程是一種人造的情況。對一個假的對象測試假的方面。不 過,這只是表明測試的不是真正的切點。仍然可以驗證建議和抽象方面所指定的 ITD 代碼。在例子中,測試驗證建議正確地編組了來自 ITD 的數(shù)據(jù)以及原來聯(lián) 結(jié)點的返回值、將它傳遞給一個工具類并返回新的結(jié)果。這涉及了相當(dāng)多的行為 。使用一個 mock 目標(biāo)還使測試更清晰了,因為測試的讀者不必閱讀真正目標(biāo)的 行為以及方面的行為。這種測試在為方面庫編寫單元測試時特別有用,因為只有 到了方面加入到具體的應(yīng)用程序中以后才會有真實的目標(biāo)。

如果將方面分解以利用這種模式的好處,那么您可能使它更具可擴展性。比 如,如果系統(tǒng)的新部分需要參與突出顯示行為,那么它們可以擴展抽象的方面并 定義覆蓋新情況的切點。這樣,抽象方面與它所建議的系統(tǒng)解耦了。

模式 2. 測試與 mock 目標(biāo)匹配的切點

針對 :橫切規(guī)范和功能

概述 :這項技術(shù)與上一技術(shù)密切相關(guān)。這次不是擴展一個抽象類,而是編寫 mock 目標(biāo),以使它匹配要測試的方面上的一個切點。可以通過檢查方面是否建 議了 mock 目標(biāo)來測試切點是否正確。如果要測試的切點過度專門化,那么可能 需要重新編寫它,使得 mock 目標(biāo)可以更容易地“預(yù)定”建議。

示例:基于一個標(biāo)志接口測試切點

不是使突出顯示方面成為抽象的,而是改寫切點使它匹配 Highlightable 接 口上的方法執(zhí)行:

public pointcut highlightedTextProperties() :
execution(public String Highlightable+.get*());

這種寬泛的切點匹配 Highlightable 上的所有 String getter。因為切點不 枚舉特定的類,它已經(jīng)匹配了 mock 目標(biāo)上的 getSomeString() 方法。測試的 其余部分保持不變。

變化:使用一個注釋

還可以編寫切點以部分根據(jù) Java 5.0 元數(shù)據(jù)進行匹配。例如,下面修改后 的切點匹配用 @Highlighted 注釋修飾的方法執(zhí)行:

public pointcut HighlightedTextProperties() :
execution(@Highlighted public String Highlightable+.*());
//you can apply the annotation in the source, or using the declare- annotation form
declare @method : public String SearchResult+.getTitle(..) : @Highlighted;
declare @method : public String SearchResult+.getProduct(..) : @Highlighted;

可以通過添加注釋到其 getSomeString() 方法,使 mock 目標(biāo)匹配新的切點 :

@Highlighted
public String getSomeString() {
return "I am a big bear!";
}

優(yōu)缺點

這項技術(shù)還明確地分離了對方面行為與目標(biāo)應(yīng)用程序的行為的測試,使測試 變?yōu)楦毩ⅰH绻悬c還沒有編寫為容納 mock 目標(biāo),那么應(yīng)當(dāng)通過重新編寫它 們得到一個耦合更松散的方面。通過使方面足夠一般化,可以影響測試類中的 mock 目標(biāo),還會保證它可以容易地讓真實類參與方面的行為。

模式 3. 驗證更復(fù)雜的切點(一個特殊情況)

針對 :橫切規(guī)范和功能

概述 :上一個 mock 目標(biāo)是簡單的,但是也可以將 mock 目標(biāo)編寫為模擬復(fù) 雜的聯(lián)結(jié)點(如 cflow())或者要影響的一系列聯(lián)結(jié)點。

例子:模擬 cflow

假定希望對于下載的報告關(guān)閉突出顯示?梢约尤胍粋 highlightExceptions切點以排除由 ReportGenerator 調(diào)用的任何 getter,如 下所示:

public pointcut highlightedTextProperties() :
execution(public String Highlightable+.get*())
&& !highlightExceptions();

public pointcut highlightExceptions() :
cflow(execution(* ReportGenerator+.*(..)));

然后可以編寫一個 mock ReportGenerator,它調(diào)用 HighlightMockTarget 以測試沒有進行突出顯示:

private class MockGenerator implements ReportGenerator {
public void write(OutputStream stream) throws IOException {
mockTarget.getSomeString();
}
}
public void testNoHighlight() throws Exception {
mockUtil.expects(never()).method("highlight");
MockGenerator accessor = new MockGenerator();
accessor.write(null);
}

不過,可以想像為更復(fù)雜的匹配情況(例如,somePointcut() && ! cflowbelow(somePointcut()))創(chuàng)建一個類似的 mock 目標(biāo)?梢暬ぞ卟荒芙o 出關(guān)于使用運行時檢查的切點(如 cflow())的匹配的詳細(xì)信息。用幾個代表性 的 mock 目標(biāo)檢查這種切點是值得的。

結(jié)束語

當(dāng)我看到未測試的代碼時,覺得厭煩。沒有好的測試集的代碼通常有很多 問題,難于進行有信任度的改變,并且難以重構(gòu)。不過,如果用方面實現(xiàn)橫切行 為,那么有了測試(并理解)應(yīng)用程序的橫切關(guān)注點的新方法。

測試方面與測試對象很相似。這兩種測試都需要將行為分解為可以單獨測試 的組件。一個要掌握的關(guān)鍵概念是橫切關(guān)注點分為兩個區(qū)域。首先是橫切規(guī)范, 它要回答的是關(guān)注點影響的是程序的哪些部分。其次是功能,它回答的是這些點 上會發(fā)生什么。如果只使用對象,那么這兩個區(qū)域是交叉的,因為關(guān)注點在應(yīng)用 程序中是糾纏在一起的。不過,使用了方面后,可以以一個領(lǐng)域為目標(biāo)或者同時 分別以兩個領(lǐng)域為目標(biāo)。

將方面編寫為可測試的,得到的設(shè)計好處與通過重構(gòu)面向?qū)ο蟮拇a來實現(xiàn) 可測試性所得到的好處相似。例如,如果將建議的正文轉(zhuǎn)移到一個可獨立測試的 類中,那么可以分析其行為而不用理解它橫切應(yīng)用程序的方式。如果修改切點 以使它們更能被 mock 目標(biāo)訪問,也使它們更可被系統(tǒng)中的非測試部分訪問。 不管是哪種情況,都提高了系統(tǒng)整體的靈活性和可插入性。

不久之前,我聽到了一個流傳的說法,說面向方面的程序不能測試。盡管這 個謠傳基本上已經(jīng)消失,我仍然認(rèn)為它是一個挑戰(zhàn)。我希望本文表明不僅可以對 方面進行測試,而且在測試橫切時,使用了方面后會好得多。

上一頁12345下一頁
軟件測試工具 | 聯(lián)系我們 | 投訴建議 | 誠聘英才 | 申請使用列表 | 網(wǎng)站地圖
滬ICP備07036474 2003-2017 版權(quán)所有 上海澤眾軟件科技有限公司 Shanghai ZeZhong Software Co.,Ltd