您的位置:軟件測試 > 開源軟件測試 > 開源單元測試工具 >
追求代碼質(zhì)量: 親身體驗行為驅(qū)動開發(fā)
作者:網(wǎng)絡(luò)轉(zhuǎn)載 發(fā)布時間:[ 2013/2/25 14:28:41 ] 推薦標(biāo)簽:

杰出的 expectation 和 override

        在清單 3 中發(fā)生的一些事情是 JBhave 特有的,所以要解釋一下。首先,我創(chuàng)建 Stack 類的一個實例,并將它限制為 String 類型(通過 Java 5 泛型)。接下來,我使用 JBehave 的 異?蚣 實際建模我所期望的行為。 Ensure 類類似于 JUnit 或 TestNG 的 Assert 類型;但是,它增加了一系列方法,提供了更具可讀性的 API(這常被稱作文學(xué)編程)。在清單 3 中,我確保了如果對 null 調(diào)用 push(),則拋出一個 RuntimeException。

        JBehave 還引入了一個 Block 類型,它是通過用所需的行為覆蓋 run() 方法來實現(xiàn)的。在內(nèi)部,JBehave 確保期望的異常類型不被拋出(并因此被捕捉),而是生成一個故障狀態(tài)。您可能還記得,在我前面關(guān)于 用 Google Web Toolkit 對 Ajax 進行單元測試 的文章中,也出現(xiàn)了類似的覆蓋便利類的模式。在那種情況下,覆蓋是通過 GWT 的 Timer 類實現(xiàn)的。

        如果現(xiàn)在運行清單 3 中的行為,應(yīng)該看到出現(xiàn)錯誤。按照目前編寫的代碼,push() 方法不執(zhí)行任何操作。所以不可能生成異常,從清單 4 中的輸出可以看到這一點。


清單 4. 沒有發(fā)生期望的行為
              
1) StackBehavior should throw exception upon null push:
VerificationException: Expected:
object not null
but got:
null:
 


        清單 4 中的句子 “StackBehavior should throw exception upon null push” 模擬行為的名稱(shouldThrowExceptionUponNullPush()),并加上類的名稱。 實際上,JBehave 是在報告當(dāng)它運行所需的行為時,沒有獲得任何反應(yīng)。當(dāng)然,我的下一步是要使上述行為成功運行,為此我檢查 null,如清單 5 所示。


清單 5. 在棧類中增加指定的行為
              
public void push(E value) {
  if(value == null){
   throw new RuntimeException("Can't push null");
  }
}
 


        當(dāng)我重新運行行為時,一切都運行得很好,如清單 6 所示。


清單 6. 成功!
              
Time: 0.021s

Total: 1. Success!
 


行為驅(qū)動開發(fā)

        清單 6 中的輸出與 JUnit 的輸出是不是很像?這也許不是巧合,對不對?如前所述,JBehave 是根據(jù) xUnit 范例建模的,它甚至通過 setUp() 和 tearDown() 提供了對 fixture 的支持。由于我可能在整個行為類中使用一個 Stack 實例,我可能也會將那種邏輯推入(這里并非有意使用雙關(guān)語)到一個 fixture 中,正如清單 7 中那樣。注意, JBehave 將與 JUnit 一樣遵循相同的 fixture 規(guī)則 — 也是說,對于每個行為方法,它都運行一個 setUp() 和 tearDown()。


清單 7. JBehave 中的 fixture
              
public class StackBehavior {
 private Stack<String> stStack;
 
 public void setUp() {
  this.stStack = new Stack<String>();
 }
 //...
}
 


        對于接下來的行為方法,shouldThrowExceptionUponPopWithoutPush() 表示我必須確保它具有類似于 清單 3 中的 shouldThrowExceptionUponNullPush() 的行為。從清單 8 中可以看出,沒有任何特別神奇的地方 — 有嗎?


清單 8. 確保 pop 的行為
              
public void shouldThrowExceptionUponPopWithoutPush() throws Exception{
 
 Ensure.throwsException(RuntimeException.class, new Block() {
   public void run() throws Exception {
    stStack.pop();
   }
 });
}
 


        您可能已經(jīng)清楚地知道,此時清單 8 并不會真正地編譯,因為 pop() 還沒有被編寫。但是,在開始編寫 pop() 之前,讓我們考慮一些事情。

確保行為

        從技術(shù)上講,在這里我可以將 pop() 實現(xiàn)為無論調(diào)用順序如何,都只拋出一個異常。但是當(dāng)我沿著這條行為路線前進時,我又忍不住考慮一個支持我所需要的規(guī)范的實現(xiàn)。在這種情況下,如果 push() 沒有被調(diào)用(或者從邏輯上講,棧為空)的情況下確保 pop() 拋出一個異常,則意味著棧有一個狀態(tài)。正如之前 Linda 思考的那樣,棧通常有一個 “內(nèi)部容器”,用于實際持有項目。相應(yīng)地,我可以為 Stack 類創(chuàng)建一個 ArrayList,用于保持傳遞給 push() 方法的值,如清單 9 所示。


        清單 9. 棧需要一種內(nèi)部的方式來持有對象
              
public class Stack<E> {
 private ArrayList<E> list;

 public Stack() {
  this.list = new ArrayList<E>();
 }
 //...
}
 


        現(xiàn)在我可以為 pop() 方法編寫行為,即確保當(dāng)棧在邏輯上為空時,拋出一個異常。


清單 10. pop 的實現(xiàn)變得更容易
              
public E pop() {
 if(this.list.size() > 0){
  return null;
 }else{
  throw new RuntimeException("nothing to pop");
 }
}
 


        當(dāng)我運行清單 8 中的行為時,一切如預(yù)期運行:由于棧中沒有存在任何值(因此它的大小不大于 0),于是拋出一個異常。

        接下來的行為方法是 shouldPopPushedValue(),這個行為方法很容易指定。我只是 push() 一個值(“test”),并確保當(dāng)調(diào)用 pop() 時,返回相同的值。

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