如果將在各種測(cè)試用例中執(zhí)行公共操作,則在測(cè)試中包括 setUp() 方法是一種很好的想法。包括 tearDown() 方法也很不錯(cuò),但不作嚴(yán)格要求,除非要運(yùn)行集成測(cè)試。
另請(qǐng)注意,使用 jMock 和 RMock,框架將在測(cè)試運(yùn)行結(jié)束時(shí)或測(cè)試運(yùn)行期間在所有模擬對(duì)象中檢查所有期望。并不實(shí)際需要為每個(gè)模擬期望包括 verify() 方法。當(dāng)作為 JUnit 測(cè)試運(yùn)行時(shí),測(cè)試將通過,如下所示:
圖 3. 場(chǎng)景 1 測(cè)試通過
ServiceTestClass 類將擴(kuò)展 jMock CGLIB 的 org.jmock.cglib.MockObjectTestCase 類。mockCollaborator 是一個(gè)十分簡(jiǎn)單的 org.jmock.JMock 類。通常,用 jMock 生成模擬對(duì)象有兩種方法:
要模擬接口,則使用 new Mock(Class.class) 方法
要模擬具體類,則使用 mock(Class.class, "identifier") 方法
必須注意的是怎樣將模擬代理 傳遞給 ServiceClass 類中的 runService() 方法。使用 jMock,您可以從已創(chuàng)建的模擬對(duì)象(其中期望已經(jīng)被設(shè)定)中提取代理實(shí)現(xiàn)。這一點(diǎn)在本文稍后的場(chǎng)景中至關(guān)重要,尤其是在涉及 RMock 的場(chǎng)景中。
回頁首
場(chǎng)景 2:使用 jMock 模擬帶有默認(rèn)構(gòu)造函數(shù)的具體類
假定 ServiceClass 類中的 runService() 方法僅接受 Collaborator 類的具體實(shí)現(xiàn)。jMock 能夠確保先前的測(cè)試通過而無需 更改期望嗎?是的,只要您能夠構(gòu)造簡(jiǎn)單默認(rèn)樣式的 Collaborator 類。
更改 ServiceClass 類中的 runService() 方法使其反映以下代碼。
清單 4. 經(jīng)過編輯的場(chǎng)景 2 的 ServiceClass 類
public class ServiceClass {
public ServiceClass(){
//no-args constructor
}
public boolean runService(Collaborator collaborator){
if("success".equals(collaborator.executeJob())){
return true;
}
else{
return false;
}
}
}
ServiceClass 類的 if...else 邏輯分支保持不變(為了清晰起見)。同時(shí),無參數(shù)構(gòu)造函數(shù)仍然適用。注,并不總是需要有創(chuàng)造性邏輯,例如 while...do 子句或 for 循環(huán)來正確地測(cè)試類的方法。只要有針對(duì)類使用的對(duì)象的方法執(zhí)行,簡(jiǎn)單的模擬期望足以測(cè)試那些執(zhí)行。
您還必須更改 ServiceClassTest 類以匹配場(chǎng)景,如下所示:
清單 5. 經(jīng)過編輯的場(chǎng)景 2 的 ServiceClassTest 類
...
private ServiceClass serviceClass;
private Mock mockCollaborator;
private Collaborator collaborator;
public void setUp(){
serviceClass = new ServiceClass();
mockCollaborator = mock(Collaborator.class, "mockCollaborator");
}
public void testRunServiceAndReturnFalse(){
mockCollaborator.expects(once()).method("executeJob").will(returnValue("failure"));
collaborator = (Collaborator)mockCollaborator.proxy();
boolean result = serviceClass.runService(collaborator);
assertFalse(result);
}
}
這里有幾點(diǎn)需要注意。第一,runService() 方法簽名已經(jīng)不同于以往。它現(xiàn)在不接受 ICollaborator 接口,而接受具體類實(shí)現(xiàn)(Collaborator 類)。測(cè)試框架而言,此更改非常重大(注,雖然在本質(zhì)上反對(duì)多態(tài),但是我們將使用傳遞具體類的示例(僅供舉例之用)。在實(shí)際的面向?qū)ο蟮膱?chǎng)景中不能這樣做)。