歡迎您光臨本站 註冊首頁

了解 JUnit 核心類、介面及生命周期

←手機掃碼閱讀     火星人 @ 2014-03-12 , reply:0
  
Junit 從問世至今已有 12 年的歷史,期間功能不斷完善,用戶逐漸擴大,已經成為 Java 軟體開發中應用最為廣泛的測試框架。本文著重介紹 JUnit 的核心介面、核心類以及 TestCase 的生命周期,以便讀者從架構層面掌握這個工具。

1997 年,Erich Gamma 和 Kent Beck 為 Java 語言創建了一個簡單但有效的單元測試框架,稱作 JUnit。JUnit 很快成為 Java 中開發單元測試的框架標準。世界上無數軟體項目使用它。本文將介紹 JUnit 的核心介面,核心類以及 JUnit 的生命周期。

JUnit 核心介面及核心類

了解 JUnit 的生命周期之前,先了解 JUnit 的核心介面和類是有必要的,這對於了解 TestCase 的生命周期有很大的幫助。

  • Test:是 TestCase、TestSuite 的共同介面。run(TestResult result) 用來運行 Test,並且將結果保存到 TestResult。

  • TestCase:Test 的介面的抽象實現,是 Abstract 類,所以不能實例化,能被繼承。其中一個構造函數 TestCase(String name),根據輸入的參數,創建一個測試實例。參數為該類的以 test 開頭的方法名,把它添加到 TestSuite 中,指定僅僅運行 TestCase 中的一個方法。

  • TestSuite:實現 Test 介面。可以組裝一個或者多個 TestCase。待測試類中可能包括了對被測類的多個 TestCase,而 TestSuit 可以保存多個 TestCase,負責收集這些測試,這樣就可以一個 Suite 就能運行對被測類的多個測試。

  • TestResult:保存 TestCase 運行中的事件。TestResult 有 List<TestFailure> fFailures 和 List<TestFailure> fErrors。fFailures 記錄 Test 運行中的 AssertionFailedError,而 fErrors 則記錄 Exception。Failure 是當期望值和斷言不匹配的時候拋出的異常,而 Error 則是不曾預料到的異常,如:ArrayIndexOutOfBoundsException。

  • TestListener:是個介面,對事件監聽,可供 TestRunner 類使用。

  • ResultPrinter:實現 TestListener 介面。在 TestCase 運行過程中,對所監聽的對象的事件以一定格式及時輸出,運行完后,對 TestResult 對象進行分析,輸出的統計結果。

  • BaseTestRunner:所有 TestRunner 的超類。

  • java Junit.swingui.TestRunner:實現 BaseTestRunner,提供圖形界面。從 4.0 版本起,就沒有再提供這個類。這是 4.0 版本和之前版本的顯著變化之一。

  • java Junit.textui.TestRunner:實現 BaseTestRunner,提供文本界面。下面將以它做為例子講解 JUnit 生命周期。





TestCase 實例

了解了前面的幾個類,下面將看一個例子:

public class TestShoppingCart extends TestCase {       double unitPrice = 5;       int quantity = 6;       double discount=0.2;         @Before       public void setUp() throws Exception {           System.out.println(" Up ");       }         @After       public void tearDown() throws Exception {           System.out.println(" Down ");       }   	      public void testPay() {           double total = unitPrice * quantity;           assertEquals(30, total);       }             public void testPayWithDiscount() {           double total = unitPrice * quantity*(1-discount);           assertEquals(24.0, total);       }  }  





兩種不同參數運行 TestCase

參數 1:

輸入:

>java junit.textui.TestRunner  TestShoppingCart

輸出:

Up   testPay!   Down   Up   testPayWithDiscount!   Down 

參數 2:

輸入:

> java junit.textui.TestRunner -m TestShoppingCart.testPayWithDiscount

輸出:

Up   testPayWithDiscount!   Down

參數 1:TestCase 名字,該類的所有的以 test 開頭的 public 方法都會執行。

參數 2:參數 -m,僅僅運行該類的該方法。

TestRunner 還提供了其他的參數 -wait:(最大響應時間),-v:查看 JUnit 版本號。從輸出可以看出,參數一: testPay(),testPayWithDiscount() 都運行;參數二:僅僅運行參數中的 testPayWithDiscount()。對比兩個輸出結果,setUp() 在每個方法運行前運行一次,teardown() 在每個方法運行后執行一次。後面將會詳細介紹。





TestRunner 處理兩種不同的參數

TestRunner main() 方法中,生成一個 TestRunner 實例,調用 start(args) 方法。在 start 方法中,JUnit 對輸入參數進行處理,首先檢查 -m、-v、-wait 等參數,對他們分別進行處理。如果有 -m 參數,將會根據“.”的位置,分割得到 className 和 methodName.

參數一:

首先調用 getTest(),通過 Java 反射實例化 TestSuite:

Class testClass = Class.forName(suiteClassName).asSubclass(TestCase.class);     new TestSuite(testClass)   

TestSuite 構造函數中,通過調用 Class.getDeclaredMethods(),得到這個類的所有 Public 的方法,當然也包括構造函數,test 開頭和非 test 開頭的 public 方法。對所有方法進行過濾,僅僅保留 public 並且以“test”開頭的方法,本例中為 testPay() 和 testPayWithDiscount()。然後分別調用 TestSuite 的 createTest() 為每個方法生成一個實例:

theClass.getConstructor(String.class).newInstance(new Object[0]);  			

並且都保存在 Vector<Test> fTests 中。

參數二:

與方法一不同的的是,並不通過反射獲得相應的方法,因為參數中指定了特定的方法。直接根據輸入參數調用 TestSuite 的 createTest(),通過反射直接生成 TestCase 實例。





TestCase 實例的運行

生成 TestCase 實例后,兩種參數都將調用 TestRunner 的 doRun() 方法。下面將對第二種參數進行詳細介紹,介紹一個 TestCase 實例是怎麼運行的,並且怎樣與 TestResult 和 TestListener 結合。

在 doRun() 方法中,實例化 TestResult result, 為 result 加上 Listener (new ResultPrinter()),用來監聽 Test 運行中的事件。然後運行 TestResult.Run(test)。run() 方法中調用 TestCase 的 runBare()。runBare() 會把所有的異常都拋出來,result 將接受到所有的異常。runBare() 首先會運行 setup(),接著運行 runTest(), 最後 tearDown()。回頭再看前面的 output,就明白了為什麼 setup() 和 tearDown() 會在每個方法運行前和后運行,對於參數二,運行了兩次。





TestResult

TestResult 有兩個 List,用來記錄 Exception 和 Failure。捕獲 runBare() 拋出的 Exception,首先判斷是否為 AssertionFailedError,是則調用 addFailure() 把,把異常加到 fFailures。否則則並調用 addError() 方法,把異常加到 fErrors 中。


[火星人 ] 了解 JUnit 核心類、介面及生命周期已經有696次圍觀

http://coctec.com/docs/linux/show-post-68791.html