JUnit 測試框架被越來越多的開發小組所共同使用歸功於各種各樣的測試裝具模塊現在可以測試構成任何 Java 應用程序的幾乎每一個組件事實上幾乎整個二級市場似乎都是用圍繞 Junit 建立的包括 CactusjfcUnitXMLUnitDbUnit 和 HttpUnit 這樣的裝具模塊都可以免費供開發人員用於測試應用程序隨著系統的復雜程度的增加並且有這麼多工具可供使用沒有什麼理由不依靠單元測試
不過開發人員不僅僅是程序員我們與用戶交互以修復 bug 並確定需求我們參加會議並進行電話推銷我們完成一些(有時全部)質量保證功能既然有這麼多責任希望盡可能自動化就是自然而然的了因為好的團隊(除了其他事情外)會進行大量測試希望自動化不同的開發過程的人常常會對這一領域進行詳細研究
自動化單元測試
有許多種自動化所有項目測試用例的定位和執行的方法一種解決方案是聯合使用 Ant 的 junit 任務與嵌入的 fileset 任務這樣就可以包括和排除特定目錄中的文件(基於文件名樣式)另一種選擇是使用 Eclipse 的一個功能它可以指定所有測試所在的和執行的目錄前一種選擇提供了對運行的測試進行過濾的靈活性(並且由於它是一個純粹的無頭(headless)Java 應用程序可以運行在幾乎所有地方)後一種選擇可以調試動態包是否可以結合這兩種方式的強大和靈活性?
有了 Python 編程語言的 Java 平台實現Jython回答是響亮的可以!(如果不熟悉 Jython開發應當在繼續本文之前補充這方面知識更多信息請參閱後面的 參考資料)利用 Jython 的強大和優雅可以維護一個定位文件系統搜索匹配某種樣式的類和動態編譯 JUnit TestSuite 類的腳本這個 TestSuite 類像所有其他靜態定義的類一樣可以用喜愛的調試程序容易地調試(在本文中使用的例子假定使用的是 Eclipse IDE不過我在這裡描述的技術不用做很多修改就可以用於大多數其他 IDE)
在進行任何設計決定時必須對所做的選擇和決定的影響進行權衡在這裡為了得到調試動態生成的測試包的能力必須增加額外的復雜性不過這種復雜性被 Jython 自身所減輕了Jython 經過很好測試並得到很好的支持並且是開放源代碼的而且Python 越來越成為面向對象的平台獨立的編程的事實上的標准出於這兩種原因采用 Jython開發 的風險很少特別是它提供了這樣的好處在創建和調試動態生成的 JUnit TestSuite 類方面具有無可匹敵的靈活性
如果是否采用 Jython 是主要的考慮那麼即使不使用它也可以在解決原來的問題方面有所進展不使用 Jython 的話可以用一個 Java Property 文件存儲一組類目錄和包以在包中加入或者排除測試不過如果選擇使用 Jython就可以利用整個 Python 語言和運行時來解決選擇執行哪些測試的問題Python 腳本比 Java Property 文件靈活得多它只受限於您的想像力
利用 Jython 與 Java 平台的無縫集成可以創建靜態定義的然而是動態構建的 TestSuite 類有大量關於 JUnit 的教程不過還是看下面這兩行代碼作為復習清單 是靜態構建 TestSuite 類的一個例子(這個例子取自 JUnit: A Cooks Tour有關它和其他 JUnit 資源的鏈接請參閱 參考資料)
清單 靜態定義 TestSuite
public static Test suite() {
return new TestSuite( MoneyTestclass )
}
清單 表明 TestSuite 是由 Test 類的類實例組成的這個裝具模塊完全利用了這一點為了分析這個工具的代碼應從 參考資料中下載本文的示例 JAR 文件這個文檔包含兩個文件DynamicTestSuitejava 和 getalltestspy前者是一個用 Phthon 腳本動態生成 TestSuite 的 JUnit 測試裝具模塊後者是一個搜索匹配特定樣式的文件的 Python 腳本DynamicTestSuitejava 使用 getalltestspy 構建 TestSuite 可以修改 getalltestspy 以更好地適合自己的項目的需要
了解測試裝具模塊
代碼是如何工作的?首先指派 getalltestspy 獲取一組要執行的 Test 類然後使用 Jython API 將這個列表從 Python 運行時環境中提取出來然後使用 Java Reflection API 構建在表示 Test 類名的列表中的 String 對象的類實例最後用 JUnit API 將 Test 添加到 TestSuite 中這四個庫的相互配合可以實現您的目標動態構建的 TestSuite 可以像靜態定義的那樣運行
看一下清單 中的 JUnit suite 清單它是一個公開 public static TestSuite suite() 方法簽名的 TestCase 由 JUnit 框架調用的 suite() 方法調用 getTestSuite() getTestSuite() 又調用 getClassNamesViaJython() 以獲取一組 String 對象其中每一個對象表示一個作為包的一部分的 TestCase 類
清單 動態定義 TestSuite
/**
* @return TestSuite A test suite containing all our tests (as found by Python script)
*/
private TestSuite getTestSuite() {
TestSuite suite = new TestSuite()
// get Iterator to class names were going to add to our Suite
Iterator testClassNames = getClassNamesViaJython()iterator()
while( testClassNameshasNext() ) {
String classname = testClassNamesnext()toString()
try {
// construct a Class object given the test case class name
Class testClass = ClassforName( classname )
// add to our suite
suiteaddTestSuite( testClass )
Systemoutprintln( Added: + classname )
}
catch( ClassNotFoundException e ) {
StringBuffer warning = new StringBuffer()
warningappend( Warning: Class )append( classname )append( not found )
Systemoutprintln( warningtoString() )
}
}
return suite;
}
在開始時要保證設置了正確的系統屬性在內部Jython 將使用 pythonhome 屬性來定位它所需要的文件最終會調用 getClassNamesViaJython() 方法在這裡面會有一些奇妙的事情發生如在清單 中將會看到的
清單 從 Python 運行時提取 Java 對象
/**
* Get list of tests were going to add to our suite
* @return List A List of String objects each representing class name of a TestCase
*/
private List getClassNamesViaJython() {
// run python script
interpreterexecfile( getPathToScript() )
// extract out Python object named PYTHON_OBJECT_NAME
PyObject allTestsAsPythonObject = interpreterget( PYTHON_OBJECT_NAME )
// convert the Python object to a String[]
String[] allTests = (String[]) allTestsAsPythonObject__tojava__( String[]class )
// add all elements of array to a List
List testList = new ArrayList()
testListaddAll( ArraysasList( allTests ) )
return testList;
}
首先對 Python 文件進行判斷然後從 Python 運行時提取出一個 PyObject 這就是得到的對象它包含將構成測試包的所有測試用例的類名(記住 PyObject 是 Python 對象的 Java 運行時對應物)然後創建具體的 List 並用 PyObject 填充它使用 __tojava__ 指示 PyObject 將其內容轉換為一個 Java String 數組最後將控制返回 getTestSuite() 在這裡裝載 Jython 標識的測試用例並將它們添加到組合包(composite)中
在Jython開發環境中安裝測試裝具模塊
現在對於測試裝具模塊如何工作已經有了很好的認識可能迫不及待要自己試試它了您將需要完成以下步驟以配置 Eclipse 來運行這個裝具模塊(如果使用不同的 IDE應當可以容易地針對您的環境修改這些步驟)
安裝 Jython 如果還沒安裝的話(鏈接請見 參考資料)
拷貝 getalltestspy 到主目錄
編輯 getalltestspy 第 行以指定到源文件的根路徑會搜索在這個位置下的所有目錄中與 org 包中 *Textjava 匹配的文件名
如果有必要修改第 行以改變根包名(例如改為 com)
將 DynamicTestSuitejava 拷貝到源樹中
將以下 JAR 添加到 Eclipse 項目中
junitjar (JUnit 框架二進制文件下載信息請參閱 JUnit 的 Web 網站)
jythonjar(Jython 二進制文件位於 Jython 安裝目錄)
將 DynamicTestSuite 類裝載到 Eclipse Java 源文件編輯器中執行以下步驟之一
在 Package Explorer 視圖中選擇 DynamicTestSuite 或者
按 Ctrl+Shift+T並在 Choose Type 輸入字段鍵入 DynamicTestSuite
從文件菜單欄選擇 Run然後選擇 Debug…
選擇 JUnit配置
單擊 New按鈕將會創建一個新的 JUnit 目標 DynamicTestSuite 應當預填入 Test Class 字段
選擇 Arguments選項卡
在 VM 參數文本框中鍵入 Dpythonhome=<path where you installed Jython>
單擊 Debug按鈕
變!現在就有了一個具體的 JUnit TestCase 類可以像靜態定義的包那樣處理它設置邊界並進行調試!不需要修改 Test 類裝具模塊將構建一個包就像您顯式將每一個 Class 對象編寫到包中一樣如要執行測試可以通過喜愛的調試器編譯工具(如 Ant 或 CruiseControl)或者一個 JUnit 內含的 test runner 調用這個裝具模塊
擴展這個裝具模塊
我相信您注意到了除非在運行前修改源代碼否則這個裝具模塊只能用於一個項目可以容易地擴展這個裝具模塊讓它支持多個項目一種簡單的方式是修改 getPathToScript() 以使用指定特定於項目的屬性的系統屬性
From:http://tw.wingwit.com/Article/program/Java/ky/201311/28944.html