第157章

大B:“剛纔說模板方法模式運用於一個業務對象。事實上,框架頻繁使用模板方法模式,使得框架實現對關鍵邏輯的集中控制。”

大B:“我們需要爲基本Spring的應用做一個測試用例的基類。用於對類的方法進行單元測試。我們知道Spring應用把需要用到的對象都定義在外部的xml文件中,也稱爲context。”

大B:“通常我們會把context分割成多個小的文件,以便於管理。在測試時我們需要讀取context文件,但是並不是每次都讀取所有的文件。讀取這些文件是很費時間的。所以我們想把它緩存起來,只要這個文件被讀取過一次,我們就把它們緩存起來。所以我們通過擴展Junit的TestCase類來完成一個測試基類。我們需要實現緩存的邏輯,其它開發人員只需要實現讀取配置文件的方法即可。它不用管是否具有緩存。”

代碼:

publicAbstractCacheContextTestsextendsTestCase{

privatestaticMapcontextMap=newHashMap();

protectedConfigurableApplicationContextapplicationContext;

protectedbooleanhasCachedContext(ObjectcontextKey){

returncontextKeyToContextMap.containsKey(contextKey);

}

protectedConfigurableApplicationContextgetContext(Objectkey){

StringkeyString=contextKeyString(key);

ConfigurableApplicationContextctx=(ConfigurableApplicationContext)contextKeyToContextMap.get(keyString);

if(ctx……null){

if(keyinstanceofString[]){

ctx=loadContextLocations((String[])key);

}

contextKeyToContextMap.put(keyString,ctx);

}

returnctx;

}

protectedStringcontextKeyString(ObjectcontextKey){

if(contextKeyinstanceofString[]){

returnStringUtils.arrayToCommaDelimitedString((String[])contextKey);

}

else{

returncontextKey.toString();

}

}

protectedConfigurableApplicationContextloadContextLocations(String[]locations){

returnnewClassPathXmlApplicationContext(locations);

}

//覆寫TestCase的setUp方法,在運行測試方法之前從緩存中讀取context文件,如果緩存中不存在則初始化applicationContext,並放入緩存。

protectedfinalvoidsetUp()throwsException{

String[]contextFiles=getConfigLocations();

applicationContext=getContext(contextFiles);

}

//讀取context文件,由子類實現

protectedabstractString[]getConfigLocations();

}

大B:“rendercode();這樣子類只需要去實現getConfigLocations方法,提供需要讀取的配置文件字符數組就可以了。至於怎麼去讀取context文件內容,怎麼實現緩存,則無需關心。AbstractCacheContextTests保證在運行所有測試之前去執行讀取context文件的動作。注意這裡setUp方法被聲明爲protected,是因爲setUp方法是TestCase類的方法。在這裡setUp方法被定義爲final了,是確保子類不能去覆寫這個方法,從而保證了父類控制的邏輯。”

小A:“如果使用過Junit會發生什麼問題?”

大B:“TestCase的setUp方法,就是在這個測試類的測試方法運行之前作一些初始化動作。如創建一些所有測試方法都要用到的公共對象等。在這裡把setUp方法聲明爲final之後,子類再也無法去擴展它了,子類同時還需要一些額外的初始化動作就無法實現了。可能你會說:‘把setUp方法的final修飾符去掉就可以了隘。這樣是可以的,但是去掉final修飾符後,子類是可以覆寫setUp方法,而去執行一些額外的初始化。而可怕的是,父類從此失去了必須讀取context文件及緩存context內容的邏輯。爲了解決這個問題,可以實現一個空方法onSetUp。在setUp方法中調用onSetUp方法。這樣子類就可以通過覆寫onSetUp方法來進行額外的初始化。”

//覆寫TestCase的setUp方法,在運行測試方法之前從緩存中讀取context文件,如果緩存中不存在則初始化applicationContext,並放入緩存。

代碼:

protected

nclass=“keyword”>finalvoidsetUp()throwsException{

String[]contextFiles=getConfigLocations();

applicationContext=getContext(contextFiles);

onSetUp();

}

protectedvoidonSetUp(){

}

//讀取context文件,由子類實現

protectedabstractString[]getConfigLocations();

}

rendercode();

小A:“爲什麼不把onSetUp聲明爲abstract呢?”

大B:“這是因爲子類不一定總是需要覆寫onSetUp方法。可以說onSetUp方法是爲了對setUp方法的擴展。像onSetUp這樣的空方法就稱之爲勾子方法(HookMethod)。”

第46章第195章第96章第84章第220章第64章第190章第147章第33章第175章第78章第35章第12章第190章第121章第19章第130章第61章第120章第133章第221章第222章第216章第17章第161章第55章第220章第26章第211章第66章第180章第182章第41章第52章第209章第205章第100章第210章第59章第100章第148章第114章第160章第106章第204章第221章第190章第222章第122章第101章第162章第126章第133章第150章第214章第155章第75章第167章第136章第159章第131章第60章第88章第207章第169章第81章第191章第57章第149章第164章第105章第124章第25章第90章第156章第96章第97章第60章第117章第202章第119章第22章第180章第185章第95章第104章第79章第78章第184章第211章第140章第20章第131章第22章第44章第18章第30章第75章第59章
第46章第195章第96章第84章第220章第64章第190章第147章第33章第175章第78章第35章第12章第190章第121章第19章第130章第61章第120章第133章第221章第222章第216章第17章第161章第55章第220章第26章第211章第66章第180章第182章第41章第52章第209章第205章第100章第210章第59章第100章第148章第114章第160章第106章第204章第221章第190章第222章第122章第101章第162章第126章第133章第150章第214章第155章第75章第167章第136章第159章第131章第60章第88章第207章第169章第81章第191章第57章第149章第164章第105章第124章第25章第90章第156章第96章第97章第60章第117章第202章第119章第22章第180章第185章第95章第104章第79章第78章第184章第211章第140章第20章第131章第22章第44章第18章第30章第75章第59章