您的位置:軟件測試 > 開源軟件測試 > 開源單元測試工具 >
追求代碼質(zhì)量: 用AOP進行防御性編程
作者:網(wǎng)絡(luò)轉(zhuǎn)載 發(fā)布時間:[ 2013/2/25 14:10:13 ] 推薦標(biāo)簽:

開發(fā)人員測試的主要缺點是:絕大部分測試都是在理想的場景中進行的。在這些情況下并不會出現(xiàn)缺陷 —— 能導(dǎo)致出現(xiàn)問題的往往是那些邊界情況。

什么是邊界情況呢?比方說,把 null 值傳入一個并未編寫如何處理 null 值的方法中,這是一種邊界情況。大多數(shù)開發(fā)人員通常都不能成功測試這樣的場景,因為這沒多大意義。但不管有沒有意義,發(fā)生了這樣的情況,會拋出一個 NullPointerException,然后整個程序會崩潰。

本月,我將為您推薦一種多層面的方法,來處理代碼中那些不易預(yù)料的缺陷。嘗試為應(yīng)用程序整合進防御性編程、契約式設(shè)計和一種叫做 OVal 的易用的通用驗證框架。

清單 1 中的代碼為給定的 Class 對象(省去了 java.lang.Object,因為所有對象都終由它擴展)構(gòu)建一個類層次。但如果仔細看的話,您會注意到一個有待發(fā)現(xiàn)的潛在缺陷,即該方法對對象值所做的假設(shè)。

    
public static Hierarchy buildHierarchy(Class clzz){

 Hierarchy hier = new Hierarchy();
 hier.setBaseClass(clzz);
 Class superclass = clzz.getSuperclass();

 if(superclass != null && superclass.getName().equals("java.lang.Object")){
  return hier;
 }else{     
  while((clzz.getSuperclass() != null) &&
    (!clzz.getSuperclass().getName().equals("java.lang.Object"))){
     clzz = clzz.getSuperclass();
     hier.addClass(clzz);
  }        
  return hier;
 }
}    


剛編好這個方法,我還沒注意到這個缺陷,但由于我狂熱地崇拜開發(fā)人員測試,于是我編寫了一個使用 TestNG 的常規(guī)測試。而且,我還利用了 TestNG 方便的 DataProvider 特性,借助該特性,我創(chuàng)建了一個通用的測試用例并通過另一個方法來改變它的參數(shù)。運行清單 2 中定義的測試用例會產(chǎn)生兩個通過結(jié)果!一切都運轉(zhuǎn)良好,不是嗎?

清單 2. 驗證兩個值的 TestNG 測試

    
import java.util.Vector;
import static org.testng.Assert.assertEquals;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

public class BuildHierarchyTest {
 
 @DataProvider(name = "class-hierarchies")
 public Object[][] dataValues(){
  return new Object[][]{
   {Vector.class, new String[] {"java.util.AbstractList",
      "java.util.AbstractCollection"}},
   {String.class, new String[] {}}
  };
 }

 @Test(dataProvider = "class-hierarchies"})
 public void verifyHierarchies(Class clzz, String[] names) throws Exception{
  Hierarchy hier = HierarchyBuilder.buildHierarchy(clzz);
  assertEquals(hier.getHierarchyClassNames(), names, "values were not equal");
 }
}


至此,我還是沒有發(fā)現(xiàn)缺陷,但一些代碼問題卻困擾著我。如果有人不經(jīng)意地為 Class 參數(shù)傳入一個 null 值會怎么樣呢?清單 1 中第 4 行的 clzz.getSuperclass() 調(diào)用會拋出一個 NullPointerException,是這樣嗎?

測試我的理論很容易;甚至都不用從頭開始。僅僅把 {null, null} 添加到初始 BuildHierarchyTest 的 dataValues 方法中的多維 Object 數(shù)組中,然后再次運行它。我定會得到如圖 1 所示的 NullPointerException:

圖 1. 可怕的 NullPointerException

防御性編程

一旦出現(xiàn)這個問題,下一步是要拿出對抗的策略。問題是我控制不了這個方法能否接收這種輸入。對于這類問題,開發(fā)人員通常會使用防御性編程技術(shù),該技術(shù)專門用來在發(fā)生摧毀性后果前捕捉潛在錯誤。

對象驗證是處理不確定性的一項經(jīng)典的防御性編程策略。相應(yīng)地,我會添加一項檢驗來驗證 clzz 是否為 null,如清單 3 所示。如果其值終為 null,我會拋出一個 RuntimeException 來警告他人注意這個潛在問題。

清單 3. 添加驗證 null 值的檢驗

    
public static Hierarchy buildHierarchy(Class clzz){
 
 if(clzz == null){
  throw new RuntimeException("Class parameter can not be null");
 }

 Hierarchy hier = new Hierarchy();
 hier.setBaseClass(clzz);

 Class superclass = clzz.getSuperclass();

 if(superclass != null && superclass.getName().equals("java.lang.Object")){
  return hier;
 }else{     
  while((clzz.getSuperclass() != null) &&
    (!clzz.getSuperclass().getName().equals("java.lang.Object"))){
     clzz = clzz.getSuperclass();
     hier.addClass(clzz);
  }        
  return hier;
 }
}    

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