綠燈 | 紅燈

妙思資訊

2011年12月26日 星期一

你開發的程式好測試嗎(四)?

第三種情況:
在Method中有new 底層的物件或服務。這些物件可能必須配合系統的環境才可生成,在測試環境也許生不出這些物件。

假設公司有一個遠端服務(remote service),當輸入計畫編號時,該服務會回傳"計畫"(Project)這個物件。因這項遠端服務具有機密性,所以只能在特定的環境下使用,在開發或測試環境是無法呼叫得到。另外這個服務的相關Class和設定都已被包在一個 Jar 檔裏。要使用這項遠端服務,只要呼叫相關的API即可,其它設定都不需更動。

這個遠端服務有一個Interface 為IRemote,並有一個getProject(String prjNo) 方法。程式碼如下:
public interface IRemote {
 
  Project getProject(String prjNo);

}

在自行開發的程式中有一項服務(AppService),需透過遠端服務來取得計畫預算,所以程式碼可能會這樣寫:
  public class AppService implements IService{
   
    public Long getPrjBudget(String prjNo){  
       IRemote remote=new RemoteProxy();
       Project project=remote.getProject(prjNo);
       return project.getBudget();
   }
}
如果程式碼是這樣寫,那測試就不會過,因為測試環境根本無法呼叫到遠端服務,而且在測試環境中,程式也跑不起來。程式中,IRemote remote=new RemoteProxy() 就跟getPrjBudget(..) 這個方法綁死無法抽換。只要在方法中有用到 new 來建立服務,那這個服務就會跟這個方法綁死而無法抽換。

如果我們把程式改寫如下:
public class AppService implements IService{
   
   private IRemote remote;
  
   public void setRemote(IRemote remote){
     this.remote=remote;
  }
 
   public Long getPrjBudget(String prjNo){  
      
       Project project=remote.getProject(prjNo);
       return project.getBudget();
   }
}

這樣遠端服務就沒有跟getPrjBudget()這個方法綁死,而是變得靈活可抽換,當測試時就可以提供假的遠端服務來測試程式的邏輯,這樣單元測試就能執行,而且在測試環境中也能夠將程式跑起來。

依環境取得AppService:
  public AppService getService(){
    
    AppService service=new AppService();
    if(isDevelopment()){
     //取得測試環境的遠端服務 
     service.setRemote(getMockRemote());
   }else{
     //取得正式環境的遠端服務
     service.setRemote(new RemoteProxy());
   }
    return service;
}


AppService 的單元測試:

 public class AppServiceTest{

 private AppService service;

 @Before
 public void setup(){
  service=new AppService();
  service.setRemote(getMockRemote());

 }   

 @Test
  public void testGetPrjBudget(){
   
   String prjNo="A123";
   Long budget=service.getPrjBudget(prjNo);
   assertTrue(budget>0);
}
  
}

沒有留言: