必須注意的是怎樣將模擬代理 傳遞給 ServiceClass 類中的 runService() 方法。使用 jMock,您可以從已創建的模擬對象(其中期望已經被設定)中提取代理實現。這一點在本文稍后的場景中至關重要,尤其是在涉及 RMock 的場景中。
場景 2:使用 jMock 模擬帶有默認構造函數的具體類
假定 ServiceClass 類中的 runService() 方法僅接受 Collaborator 類的具體實現。jMock 能夠確保先前的測試通過而無需 更改期望嗎?是的,只要您能夠構造簡單默認樣式的 Collaborator 類。
更改 ServiceClass 類中的 runService() 方法使其反映以下代碼。
清單 4. 經過編輯的場景 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 邏輯分支保持不變(為了清晰起見)。同時,無參數構造函數仍然適用。注,并不總是需要有創造性邏輯,例如 while...do 子句或 for 循環來正確地測試類的方法。只要有針對類使用的對象的方法執行,簡單的模擬期望就足以測試那些執行。
您還必須更改 ServiceClassTest 類以匹配場景,如下所示:
清單 5. 經過編輯的場景 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);
}
}
這里有幾點需要注意。第一,runService() 方法簽名已經不同于以往。它現在不接受 ICollaborator 接口,而接受具體類實現(Collaborator 類)。就測試框架而言,此更改非常重大(注,雖然在本質上反對多態,但是我們將使用傳遞具體類的示例(僅供舉例之用)。在實際的面向對象的場景中絕對不能這樣做)。
第二,模擬 Collaborator 類的方式已經更改。使用 jMock CGLIB 庫可以模擬具體類實現。提供給 jMock CGLIB 的 mock() 方法的附加 String 參數被用作創建的模擬對象的標識符。使用 jMock(當然,還有 RMock)時,在單一測試用例內每個模擬對象設置都要求有惟一標識符。這對于在公共的 setUp() 方法中或在實際測試方法內定義的模擬對象來說是正確的。
第三,測試方法的原始期望并未更改。仍然要求有 false 證明才能使測試通過。這是十分重要的,因為通過展示使用的測試框架足夠靈活、可以適應各種輸入帶來的更改、同時仍然允許獲得不變的測試結果,使它們在無法調節輸入生成同樣的結果時展示了其實際限制。
現在,重新運行作為 JUnit 測試的測試。測試將通過,如下所示:
圖 4. 場景 2 測試通過
在下一個場景中,情況會變得略微復雜一些。您將使用 RMock 框架來相對緩解一下這種困難的情形。
文章來源于領測軟件測試網 http://www.kjueaiud.com/