在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);
}
}
沒有留言:
張貼留言