国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開(kāi)發(fā)設(shè)計(jì) > 正文

進(jìn)行記錄器測(cè)試以正確調(diào)用方法

2019-11-18 14:56:51
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

  寫(xiě)下確保方法調(diào)用按正確順序發(fā)生的單元測(cè)試的記錄器
Eric E. Allen (eallen@cs.rice.edu)
博士研究生,java 編程語(yǔ)言小組,Rice 大學(xué)


用 JUnit 進(jìn)行單元測(cè)試是一個(gè)功能強(qiáng)大的方法,它可以確保您的代碼基礎(chǔ)的完整性,但是一些不變量比其他(方法調(diào)用序列是其中一種)更難測(cè)試。在診斷 Java 代碼這一部分,Eric Allen 描述了怎樣在您的單元測(cè)試中使用記錄器(一種非凡的偵聽(tīng)器),來(lái)確保一個(gè)方法調(diào)用序列按恰當(dāng)?shù)捻樞虬l(fā)生。請(qǐng)點(diǎn)擊文章頂部和底部的討論,與作者和其他讀者在論壇上分享您關(guān)于本文的看法。
隨著時(shí)間的推移,當(dāng)系統(tǒng)開(kāi)發(fā)人員,維護(hù)人員甚至是系統(tǒng)具體說(shuō)明改變時(shí),JUnit 框架提供一個(gè)很好的方法來(lái)改善系統(tǒng)的堅(jiān)固性。通過(guò)測(cè)試,您可以檢查到代碼的某些不變量是受支持的。

測(cè)試通常分為兩類:?jiǎn)卧徒邮軠y(cè)試:

單元測(cè)試確保組成組件完成其應(yīng)完成的功能。


接受測(cè)試確保系統(tǒng)的最高級(jí)功能出現(xiàn)在用戶面前時(shí),與它設(shè)計(jì)時(shí)的功能一致。



JUnit 可幫助進(jìn)行單元測(cè)試。

代碼快速跟蹤
清單 1. 同客戶端通信的三個(gè)類
Greeter 類建立和中斷同外部客戶端的連接。Sender 類發(fā)送各種消息。 Coordinator 類治理另外兩個(gè)類的實(shí)例,確保它們一起工作。

清單 2. 在每個(gè)對(duì)象中安裝相同的記錄器
通過(guò)將相同的、非凡的 Listener(稱為 記錄器)安裝到每一個(gè)對(duì)象中,可以決定這些對(duì)象中方法的調(diào)用順序。

清單 3. 一個(gè) JUnit 測(cè)試
將消息存儲(chǔ)為簡(jiǎn)單的 String,用這種簡(jiǎn)單的測(cè)試檢查 playBack 的內(nèi)容已能夠滿足我們的需要,而不必建立一個(gè)測(cè)試來(lái)檢查記錄的實(shí)例的每個(gè)可能反復(fù)。

理想情況下,為系統(tǒng)開(kāi)發(fā)的單元測(cè)試會(huì)完全覆蓋組成部分的預(yù)期不變量的設(shè)置,并能確保新的開(kāi)發(fā)人員所作的任何更改都不會(huì)破壞現(xiàn)有代碼。

實(shí)際上,一些不變量將會(huì)被測(cè)試忽略。部分原因是一些不變量在沒(méi)達(dá)到全面的系統(tǒng)測(cè)試水平時(shí),陷入到系統(tǒng)的許多孤立組件的交互作用中。

在本文中,我將討論一個(gè)那種類型的不變量以及如何使用一個(gè)復(fù)雜的單元測(cè)試來(lái)檢查此不變量。我要討論的不變量類型是一組相關(guān)方法序列調(diào)用的恰當(dāng)順序。

與 JUnit 握手
在繼續(xù)之前,熟悉 JUnit 和學(xué)會(huì)怎樣輕松使用它來(lái)為您的代碼寫(xiě)單元測(cè)試非常重要。在參考資料一節(jié),我已經(jīng)包括了一個(gè)鏈接,它能鏈接到下載和開(kāi)始使用 JUnit 所需要的所有信息。(假如您熟悉 JUnit,請(qǐng)直接跳到第 1 個(gè)示例。)

單元測(cè)試為開(kāi)發(fā)人員提供下列功能:

從接口透視圖設(shè)計(jì)類
除去發(fā)行包中的類混亂
自動(dòng)確認(rèn)捕捉變化的錯(cuò)誤
單元測(cè)試過(guò)程通常按照以下步驟進(jìn)行:

決定您的組件該做什么。


正式地(或非正式地,取決于復(fù)雜性)設(shè)計(jì)您的組件。


寫(xiě)出單元測(cè)試來(lái)檢查組件的活動(dòng)。(在這一步,測(cè)試將不編譯;代碼還沒(méi)寫(xiě)。寫(xiě)測(cè)試的目的是用來(lái)幫助確定組件的功能目的。)


按設(shè)計(jì)寫(xiě)出組件代碼;假如有必要,則進(jìn)行單元重組。


當(dāng)測(cè)試(從第 3 步開(kāi)始)通過(guò)后,停止編碼過(guò)程。


集體討論其它的代碼中斷的可能性;寫(xiě)出測(cè)試進(jìn)行確認(rèn),然后修改代碼。


每次探測(cè)到一個(gè)缺陷就要寫(xiě)一個(gè)新的測(cè)試。


每次改動(dòng)代碼后都要重新開(kāi)始全部測(cè)試。
JUnit 是由 Erich Gamma 和 Kent Beck 創(chuàng)建的一個(gè)簡(jiǎn)單構(gòu)架,可用來(lái)編寫(xiě)可重復(fù)的測(cè)試,它使得構(gòu)造一個(gè)可增加改動(dòng)的測(cè)試套件變得相對(duì)簡(jiǎn)單,該測(cè)試套件可幫助開(kāi)發(fā)人員評(píng)估開(kāi)發(fā)的進(jìn)展以及探測(cè)非故意的影響。JUnit 是 xUnit 架構(gòu)的一個(gè)實(shí)例。

有了 JUnit,每個(gè)測(cè)試實(shí)例繼續(xù)了 TestCase 類。其中名字以 "test" 開(kāi)始的每個(gè)無(wú)參數(shù)的公共方法每次執(zhí)行一次。測(cè)試方法調(diào)用測(cè)試下的組件,并對(duì)該組件的行為做出斷言。在不能做出斷言的時(shí)候,JUnit 還會(huì)報(bào)告失敗的位置。

由于以下的原因,JUnit 尤其有用:

它是一個(gè)完整的、開(kāi)放源代碼的產(chǎn)品;您不必自己寫(xiě)或購(gòu)買一個(gè)框架。
因?yàn)樗枪_(kāi)源代碼的,所以它的許多用戶都是很有經(jīng)驗(yàn)的。
它答應(yīng)您從產(chǎn)品代碼中分離出測(cè)試代碼。
在構(gòu)建過(guò)程中很輕易整合。
現(xiàn)在,您已經(jīng)了解了 JUnit,讓我們看一個(gè)示例。

Greeters 和 Senders
考慮下面的示例,它將給外部客戶端發(fā)送不同的消息:

清單 1. 同客戶端通信的三個(gè)類

public class Greeter {
public void sayHello() {...}
public void sayGoodbye() {...}
}

public class Sender {
public void sendFirstMessage() {...}
public void sendSecondMessage() {...}
}

public class Coordinator extends Thread {

Sender s;
Greeter g;

public Coordinator(Sender _s, Greeter _g) {
this.s = _s;
this.g = _g;
}

public void run() {
g.sayHello();
s.sendFirstMessage();
s.sendSecondMessage();
g.sayGoodbye();
}
}






第一個(gè)類,Greeter,負(fù)責(zé)建立和中斷與外部客戶端的連接。第二個(gè)類, Sender,負(fù)責(zé)給客戶端發(fā)送不同的消息。第三個(gè)類,Coordinator,治理另外兩個(gè)類的實(shí)例,確保它們共同合作同客戶端進(jìn)行通信。

勿庸置疑,按適當(dāng)?shù)捻樞蛘{(diào)用這些方法是至關(guān)重要的。但是將來(lái)的擴(kuò)展和代碼的單元重組可能會(huì)不經(jīng)意間改變方法調(diào)用的順序。例如,另一個(gè)開(kāi)發(fā)人員可能將 Greeter 和 Sender 方法的調(diào)用移到單獨(dú)的線程中,使用信號(hào)來(lái)控制調(diào)用它們的順序。

不管發(fā)生什么改變,我們要怎樣將測(cè)試放在我們的套件,才能保證在任何情況下都能按正確的順序調(diào)用方法呢?與許多單元測(cè)試不同,我們不能僅僅調(diào)用這些方法并檢查結(jié)果,因?yàn)槲覀兿胍獧z查的,并不是使用其中任何一個(gè)方法得出的結(jié)果。

記錄您的下一偉大的步驟…
解決方法是使用一個(gè)非凡類型的偵聽(tīng)器,我們稱之為 Recorder (記錄器)。記錄器保存它們所注冊(cè)的每個(gè)對(duì)象上的每個(gè)方法調(diào)用。

記錄器按方法被調(diào)用的順序線性地保存這些記錄,這非常象一個(gè)盒式磁帶。通過(guò)將相同的 Recorder 安裝到每一個(gè)對(duì)象中,可以檢查這些對(duì)象中方法的調(diào)用順序。請(qǐng)考慮下面的代碼:

清單 2. 在每個(gè)對(duì)象中安裝相同的 Recorder

public class Recorder {

PRivate StringBuffer tape;


public Recorder() {
this.tape = new StringBuffer();
}

public String playBack() {
return tape.toString();
}

public void record(String s) {
tape.append(s);
}
}

public class Greeter {

private Recorder r;

public Greeter(Recorder _r) {
this.r = _r;
}

public void sayHello() {
r.record("sayHello();");
...
}
public void sayGoodbye() {
r.record("sayGoodbye();");
...
}
}

public class Sender {

private Recorder r;

public Sender(Recorder _r) {
this.r = _r;
}

public void sendFirstMessage() {
r.record("sendFirstMessage();");
...
}
public void sendSecondMessage() {
r.record("sendSecondMessage();");
...
}
}






用 String 還是 ToString
注重 Sender 和 Greeter 中的每一個(gè)方法必須向 Recorder 通報(bào)新方法的調(diào)用。在這種方法下,記錄器就像其他偵聽(tīng)器一樣:任何改變發(fā)生時(shí)都必須通知它們。

另外,注重被傳送到 Recorder 的消息是一個(gè)簡(jiǎn)單的 String。使用 String 消息有利也有弊。一方面,一個(gè)較復(fù)雜的對(duì)象在每一種方法調(diào)用時(shí)都能被保存下來(lái),提供更具體的信息。另一方面,這么復(fù)雜的對(duì)象將使得測(cè)試工作更加困難。

例如,使用清單 2 中的記錄器,只要把下面簡(jiǎn)單的測(cè)試加到我們的套件中,就能決定調(diào)用的順序:

清單 3. 一個(gè) JUnit 測(cè)試

public void testOrderOfInvocation() throws InterruptedException {
Recorder r = new Recorder();
Greeter g = new Greeter(r);
Sender s = new Sender(r);
Coordinator c = new Coordinator(s, g);
c.start();
c.join();
assertEquals("sayHello();sendFirstMessage();sendSecondMessage();
sayGoodbye();",r.playBack());
}






由于我們已經(jīng)將消息保存為簡(jiǎn)單的 String 型變量 s,檢查 playBack 的內(nèi)容的測(cè)試就很簡(jiǎn)單:只要寫(xiě)出正確的 String,然后與之對(duì)照檢查就可以了。

另一方面,假如我們已經(jīng)使用了一個(gè)較復(fù)雜類型的對(duì)象,我們不得不為這些對(duì)象中的每一個(gè)都構(gòu)造一個(gè)同樣的實(shí)例,并重述所有記錄過(guò)的實(shí)例,檢查它們之中每一個(gè)的等同性。另外,這還需要我們?yōu)橛涗涍^(guò)的對(duì)象的每個(gè)類寫(xiě)一個(gè) equals 方法。

像這樣的話,一次測(cè)試要做很多工作。我不知道您怎么樣,但是我寧愿把時(shí)間花在寫(xiě)更多較簡(jiǎn)單的測(cè)試上(設(shè)計(jì)代碼使得它們更輕易),而不愿為我的測(cè)試寫(xiě)基礎(chǔ)結(jié)構(gòu)的代碼。

這兩種方法間的一個(gè)折衷是制作另一個(gè) Recorder,它可以存儲(chǔ)非常復(fù)雜的數(shù)據(jù),但有一個(gè)簡(jiǎn)單的 toString 方法可用來(lái)測(cè)試,就如上面提到的那個(gè)。于是,較復(fù)雜的數(shù)據(jù)可用于其他的測(cè)試,檢查調(diào)用序列的具體屬性。

預(yù)備好測(cè)試
用 Recorder 進(jìn)行測(cè)試的思想可應(yīng)用到許多類型的測(cè)試中:

除檢查調(diào)用的簡(jiǎn)單順序之外,記錄器可在分布環(huán)境中使用,確保通信中不同的不變量在相互通信過(guò)程中保持不變。


記錄器也可用來(lái)和 GUI 一起確保響應(yīng)各種預(yù)期的用戶操作。
簡(jiǎn)而言之,記錄器提供了一種測(cè)試組件集合體的方法,它比大多數(shù)單元測(cè)試覆蓋的范圍大,但還是比整個(gè)系統(tǒng)小。我希望您能和我一樣,覺(jué)得它有用。

參考資料

請(qǐng)點(diǎn)擊文章頂部或底部的討論,參與關(guān)于本文的討論論壇。


JUnit 主頁(yè) 提供了大量關(guān)于 JUnit 和相關(guān)主題的信息。


Malcolm Davis 所著的“使用 Ant 和 JUnit 進(jìn)行遞增開(kāi)發(fā)”(developerWorks,2000 年 11 月)討論了怎樣將這些工具集成到您的開(kāi)發(fā)環(huán)境中去。


假如喜歡 JUnit,您可能想要檢查全部面向多種語(yǔ)言的 xUnit 測(cè)試工具。


xUnit 工具套件是與極限編程 (XP) 一起使用的,極限編程是一種新的功能強(qiáng)大的方法,可快速開(kāi)發(fā)整潔堅(jiān)固的軟件。


關(guān)于 XP 的快速初級(jí)讀本,請(qǐng)查閱由 Roy Miller 和 Chris Collins (developerWorks,2001 年 3 月)合著的 “XP 精華”。


使用 VAJ 開(kāi)發(fā)?Allison Pearce Wilson 提供了大量的關(guān)于 VAJ 和 XP 的資料。


" The UML Profile for Framework Architectures"(以 PDF 幻燈片格式)重點(diǎn)介紹了 JUnit 的具體案例分析。


關(guān)于作者
Eric Allen 畢業(yè)于 Cornell 大學(xué),獲得計(jì)算機(jī)科學(xué)和數(shù)學(xué)的學(xué)士學(xué)位。他目前是 Cycorp,Inc. Java 軟件開(kāi)發(fā)的負(fù)責(zé)人,并是 Rice 大學(xué)的編程語(yǔ)言小組的一個(gè)兼職研究生。他的研究涉及在源程序和字節(jié)碼層次上的 Java 語(yǔ)言的語(yǔ)義模型和靜態(tài)分析工具的開(kāi)發(fā)。目前,他正在為 NextGen 編程語(yǔ)言(類屬運(yùn)行類型的 Java 語(yǔ)言擴(kuò)展)實(shí)現(xiàn)一個(gè)源程序到字節(jié)碼的編譯器。可通過(guò) eallen@cyc.com 聯(lián)系 Eric。

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 灵山县| 长武县| 陆川县| 卢氏县| 洛隆县| 泰安市| 通城县| 兴仁县| 修武县| 鄂尔多斯市| 巨野县| 南投县| 安顺市| 肃宁县| 西盟| 富锦市| 肥城市| 建湖县| 惠安县| 咸丰县| 玛纳斯县| 常山县| 蓝田县| 渭南市| 汪清县| 金平| 来安县| 新建县| 永德县| 新宁县| 中卫市| 四平市| 贵阳市| 台南县| 北辰区| 肥西县| 周至县| 烟台市| 哈巴河县| 临沂市| 来宾市|