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

為 OVal 鋪好了路、為 AOP 過(guò)程做了引導(dǎo)之后,可以開(kāi)始使用 Java 5 標(biāo)注來(lái)為代碼指定簡(jiǎn)單的約束條件了。

OVal 的可重用約束條件

用 OVal 為方法指定前置條件必須對(duì)方法參數(shù)進(jìn)行標(biāo)注。相應(yīng)地,當(dāng)調(diào)用一個(gè)用 OVal 約束條件標(biāo)注過(guò)的方法時(shí),OVal 會(huì)在該方法真正執(zhí)行前 驗(yàn)證該約束條件。

在我的例子中,我想要指定當(dāng) Class 參數(shù)的值為 null 時(shí),buildHierarchy 方法不能被調(diào)用。OVal 通過(guò) @NotNull 標(biāo)注支持此約束條件,該標(biāo)注在方法所需的所有參數(shù)前指定。也要注意,任何想要使用 OVal 約束條件的類也必須在類層次上指定 @Guarded 標(biāo)注,像我在清單 7 中所做的那樣:

清單 7. OVal 約束條件

    
import net.sf.oval.annotations.Guarded;
import net.sf.oval.constraints.NotNull;

@Guarded
public class HierarchyBuilder { 

 public static Hierarchy buildHierarchy(@NotNull 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;
  }
 }     
}


通過(guò)標(biāo)注指定這個(gè)約束條件意味著我的代碼不再會(huì)被重復(fù)的條件弄得亂七八糟,這些條件檢查 null 值,并且一旦找到該值會(huì)拋出異!,F(xiàn)在這項(xiàng)邏輯由 OVal 處理,且處理的方法有些相似 —— 事實(shí)上,如果違反了約束條件,OVal 會(huì)拋出一個(gè) ConstraintsViolatedException,它是 RuntimeException 的子類。

當(dāng)然,我下一步要編譯 HierarchyBuilder 類和 清單 5 中相應(yīng)的 DefaultGuardAspect 類。我用 清單 6 中的 iajc 任務(wù)來(lái)實(shí)現(xiàn)這一目的,這樣我能把 OVal 的行為編入我的代碼中了。

接下來(lái),我更新 清單 4 中的測(cè)試用例來(lái)驗(yàn)證是否拋出了一個(gè) ConstraintsViolatedException,如清單 8 所示:

清單 8. 驗(yàn)證是否拋出了 ConstraintsViolatedException

    
@Test(expectedExceptions={ConstraintsViolatedException.class})
public void verifyHierarchyNull() throws Exception{
 Class clzz = null;
 HierarchyBuilder.buildHierarchy(clzz);  
}


指定后置條件

正如您所見(jiàn),指定前置條件其實(shí)相當(dāng)容易,指定后置條件的過(guò)程也是一樣。例如,如果我想對(duì)所有調(diào)用 buildHierarchy 的程序保證它不會(huì)返回 null 值(這樣,這些調(diào)用程序不需要再檢查這個(gè)了),我可以在方法聲明之上放置一個(gè) @NotNull 標(biāo)注,如清單 9 所示:

清單 9. OVal 中的后置條件

    
    @NotNull
public static Hierarchy buildHierarchy(@NotNull Class clzz){  
 //method body
}


當(dāng)然,@NotNull 絕不是 OVal 提供的惟一約束條件,但我發(fā)現(xiàn)它能非常有效地限制這些令人討厭的 NullPointerException,或至少能夠快速地暴露 它們。

更多的 OVal 約束條件

OVal 也支持在方法調(diào)用前或后對(duì)類成員進(jìn)行預(yù)先驗(yàn)證。這種機(jī)制具有限制針對(duì)特定約束條件的重復(fù)條件測(cè)試的好處,如集合大小或之前討論過(guò)的非 null 的情況。

例如,在清單 10 中,我使用 HierarchyBuilder 定義了一個(gè)為類層次構(gòu)建報(bào)告的 Ant 任務(wù)。請(qǐng)注意 execute() 方法是如何調(diào)用 validate 的,后者會(huì)依次驗(yàn)證 fileSet 類成員是否含值;如果不含,會(huì)拋出一個(gè)異常,因?yàn)闆](méi)有了要評(píng)估的類,該報(bào)告不能運(yùn)行。

清單 10. 帶條件檢驗(yàn)的 HierarchyBuilderTask

    
public class HierarchyBuilderTask extends Task {
 private Report report;
 private List fileSet;

 private void validate() throws BuildException{
  if(!(this.fileSet.size() > 0)){
   throw new BuildException("must supply classes to evaluate");
  }
  if(this.report == null){
   this.log("no report defined, printing XML to System.out");
  }
 }

 public void execute() throws BuildException {
  validate();
  String[] classes = this.getQualifiedClassNames(this.fileSet);
  Hierarchy[] hclz = new Hierarchy[classes.length];

  try{
   for(int x = 0; x < classes.length; x++){
    hclz[x] = HierarchyBuilder.buildHierarchy(classes[x]);            
   }       
   BatchHierarchyXMLReport xmler = new BatchHierarchyXMLReport(new Date(), hclz);
   this.handleReportCreation(xmler);
  }catch(ClassNotFoundException e){
   throw new BuildException("Unable to load class check classpath! " + e.getMessage());
  } 
 }
//more methods below....
}

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