第二,模擬 Collaborator 類的方式已經更改。使用 jMock CGLIB 庫可以模擬具體類實現。提供給 jMock CGLIB 的 mock() 方法的附加 String 參數被用作創建的模擬對象的標識符。使用 jMock(當然,還有 RMock)時,在單一測試用例內每個模擬對象設置都要求有惟一標識符。這對于在公共的 setUp() 方法中或在實際測試方法內定義的模擬對象來說是正確的。
第三,測試方法的原始期望并未更改。仍然要求有 false 證明才能使測試通過。這是十分重要的,因為通過展示使用的測試框架足夠靈活、可以適應各種輸入帶來的更改、同時仍然允許獲得不變的測試結果,使它們在無法調節輸入生成同樣的結果時展示了其實際限制。
現在,重新運行作為 JUnit 測試的測試。測試將通過,如下所示:
圖 4. 場景 2 測試通過
在下一個場景中,情況會變得略微復雜一些。您將使用 RMock 框架來相對緩解一下這種困難的情形。
場景 3:使用 jMock 和 RMock 模擬帶有非默認構造函數的具體類
首先像以前一樣嘗試使用 jMock 來模擬 Collaborator 對象 —— 只是這一次,Collaborator 沒有默認的無參數構造函數。注,保留布爾 false 結果的測試期望。
同時假定 Collaborator 對象要求使用字符串和原始的 int 作為傳遞給構造函數的參數。清單 6 顯示了對 Collaborator 對象所做的更改。
清單 6. 經過編輯的場景 3 的 Collaborator 類
public class Collaborator{
private String collaboratorString;
private int collaboratorInt;
public Collaborator(String string, int number){
collaboratorString = string;
collaboratorInt = number;
}
public String executeJob(){
return "success";
}
}
Collaborator 類構造函數仍然十分簡單。用傳入參數設定類字段。這里不必使用任何其他邏輯,并且其 executeJob() 函數保持不變。
重新運行測試,并且示例的所有其他組件保持不變。結果是災難性的測試失敗,如下所示:
圖 5. 場景 3 測試失敗
以上測試是作為簡單的 JUnit 測試運行的,沒有代碼覆蓋。您可以用大多數代碼覆蓋工具(例如,Cobertura 或 EclEmma)來運行本文中列出的任何一個測試。但是,用 Eclipse 內的代碼覆蓋工具運行 RMock 測試時會帶來一些問題(參見 表 1)。以下代碼顯示了實際堆棧跟蹤的代碼片段。
清單 7. 場景 3 中測試失敗的堆棧跟蹤
...Superclass has no null constructors but no arguments were given
at net.sf.cglib.proxy.Enhancer.emitConstructors(Enhancer.java:718)
at net.sf.cglib.proxy.Enhancer.generateClass(Enhancer.java:499)
at net.sf.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:216)
at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:377)
at net.sf.cglib.proxy.Enhancer.create(Enhancer.java:285)
at net.sf.cglib.proxy.Enhancer.create(Enhancer.java:660)
.....
.....
失敗原因是 jMock 無法通過沒有無參數構造函數的類定義創建可行的模擬對象。實例化 Collaborator 對象的惟一方法是提供兩個簡單參數。您現在必須找到一種方法把參數提供給模擬對象實例化過程以達到同樣的效果,這是使用 RMock 的原因。
用 RMock 測試框架更正失敗的測試
要更正測試,必須執行一些修改。這些更改可能顯得十分重要,但是實際上,它們是一種相對簡單的解決方法,利用兩種框架的強大功能來實現目的。