使用模擬對象(Mock Object)技術進行測試驅動開發

測試驅動開發是敏捷開發中重要部分。在現實項目中,開發人員通常希望減少對其它模塊的依賴,把測試的單元與系統其它單元隔離。本文介紹敏捷開發並探討測試驅動開發的重要性。對 mock 技術進行理論分析,並結合當前流行的 mock 軟件如 jMock 和 EasyMock 等,展示測試驅動開發實例並進行比較。

敏捷開發

敏捷軟件開發又稱敏捷開發,是一種從上世紀 90 年代開始引起開發人員注意的新型軟件開發方法。和傳統瀑布式開發方法對比,敏捷開發強調的是在幾周或者幾個月很短的時間週期,完成相對較小功能,並交付使用。在項目週期內不斷改善和增強。

2001 年初,在美國猶他州雪鳥滑雪勝地,17 名編程大師分別代表極限編程、Scrum、特徵驅動開發、動態系統開發方法、自適應軟件開發、水晶方法、實用編程等開發流派,發表“敏捷軟件開發”宣言。其內容主要包括:

  • 人和交互重於過程和工具;
  • 可以工作的軟件重於求全責備的文檔;
  • 客戶協作重於合同談判;
  • 隨時應對變化重於循規蹈矩;

可見在敏捷軟件開發中,交付高質量的軟件是非常重要的。只有交付可以工作的軟件,開發人員才能不斷地完成更多功能,而不是將大部分時間投入在修復軟件產品缺陷 (Bug) 。所以如何提高交付軟件的質量,在敏捷開發實施過程非常重要。





回頁首


測試驅動開發

測試驅動開發,它是敏捷開發的最重要的部分。方法主要是先根據客戶的需求編寫測試程序,然後再編碼使其通過測試。在敏捷開發實施中,開發人員主要從兩個方面去理解測試驅動開發。

  • 在測試的輔助下,快速實現客戶需求的功能。通過編寫測試用例,對客戶需求的功能進行分解,並進行系統設計。我們發現從使用角度對代碼的設計通常更符合後期開發的需求。可測試的要求,對代碼的內聚性的提高和複用都非常有益。
  • 在測試的保護下,不斷重構代碼,提高代碼的重用性,從而提高軟件產品的質量。可見測試驅動開發實施的好壞確實極大的影響軟件產品的質量,貫穿了軟件開發的始終。

在測試驅動開發中,爲了保證測試的穩定性,被測代碼接口的穩定性是非常重要的。否則,變化的成本就會急劇的上升。所以,自動化測試將會要求您的設計依賴於接口,而不是具體的類。進而推動設計人員重視接口的設計,體現系統的可擴展性和抗變性。





回頁首


利用僞對象 (Mock Obect) 實現接口測試

在實施測試驅動開發過程中,我們可能會發現需要和系統內的某個模塊或系統外某個實體交互,而這些模塊或實體在您做單元測試的時候可能並不存在,比如您遇到了數據庫,遇到了驅動程序等。這時開發人員就需要使用 MO 技術來完成單元測試。

最開始,Mock Object 是完全由測試者自己手工撰寫的。在這裏我們可以舉個簡單的例子。

我們有一個移動數字電視卡的接口程序。


清單 1. VideoCardInterface 代碼
				
public interface VideoCardInterface {

public void open();

public void changeChannel(int i);

public void close();

public Byte[] read();

public boolean fault();
}

下面是每個方法的功能說明:

  • open 打開移動數字電視卡。
  • changeChannel 切換移動數字電視頻道。必須在打開之後纔可以正常工作,否則就提示錯誤信息。
  • close 關閉移動移動電視卡。必須在打開之後纔可以正常工作,否則就提示錯誤信息。
  • read 讀取字節流。必須在打開之後纔可以正常工作,否則就提示錯誤信息。
  • fault 顯示當前工作狀態。

由於相對應的硬件開發工作還沒有完成,我們無法基於這樣的接口程序進行實際的測試。所以開發人員基於接口,實現了部分移動電視卡的邏輯。


清單 2. MockVCHandler 代碼
				
public class MockVCHandler implements VideoCardInterface {

private boolean initialized = false;
private boolean error = false;
private int channel;
private static final int DEFAULTCHANNEL = 1;

public void open() {
initialized = true;
channel = DEFAULTCHANNEL;
}

public void changeChannel(int i) {
if (!initialized) {
Assert.fail("Trying to change channel before open");
}
if (i <= 0) {
Assert.fail("Specified channale is out-of-range");
}
this.channel = i;
}

public void close() {
if (!initialized) {
Assert.fail("Trying to close before open");
}
}

public Byte[] read() {
if (!initialized) {
Assert.fail("Trying to read before open");
return null;
}
if (channel > 256) {
error = true;
Assert.fail("Channel is out-of-range");
}
return new Byte[] { '0', '1' };
}

public boolean fault() {
return error;
}
}

通過以上的實現,我們可以測試每個動作之間的先後邏輯關係,同時可以測試數據流讀取出錯的邏輯。如果測試人員進一步對數據流進行測試。還可以自我生成一段二進制字節流並進行測試。通過以上的實現,我們可以大大加快開發進度。在傳統開發流程中,軟件開發和測試不得不等大部分硬件都已經可以使用的條件下纔可以開發測試。使用 MO 技術,使得硬件和軟件在一定程度上可以同步開發和測試。

但是測試人員完全依靠自己實現這些類,不可避免的會帶來測試用例編寫效率低下和測試用例編寫困難的弊病,甚至可能會影響 XP 實踐者“測試先行”的激情。此時,各種各樣幫助創建 Mock Object 的工具就應運而生了。目前,在 Java 陣營中主要的 Mock 測試工具有 jMock,MockCreator,MockRunner,EasyMock,MockMaker 等,在微軟的 .Net 陣營中主要是 NMock,.NetMock,Rhino Mocks 和 Moq 等。





回頁首


jMock 框架介紹

總體上來說,jMock 是一個輕量級的模擬對象技術的實現。它具有以下特點:

  • 可以用簡單易行的方法定義模擬對象,無需破壞本來的代碼結構表;
  • 可以定義對象之間的交互,從而增強測試的穩定性;
  • 可以集成到測試框架;
  • 易擴充;

與大多數 MOCK 框架一樣,我們可以在 IDE 中使用並進行開發。本文以最常用的 Eclipse 爲例。

下載 jMock

在 jMock 官方網站,我們可以下載當前穩定版本 jMock2.5.1 。

配置類路徑

爲了使用 jMock 2.5.1,您需要加入下面的 JAR 文件到當前的類路徑。

  • jmock-2.5.1.jar
  • hamcrest-core-1.1.jar
  • hamcrest-library-1.1.jar

圖 1. 已添加到 TestingExample 項目中 jMock 的 JAR 文件



本文轉自IBM Developerworks中國

      請點擊此處查看全文

 
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章