熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java開源技術 >> 正文

Java標准單元測試庫 JUnit 4 搶先看

2013-11-23 20:40:28  來源: Java開源技術 

  JUnit 是 Java? 語言事實上的 標准單元測試庫JUnit 是該庫三年以來最具裡程碑意義的一次發布它的新特性主要是通過采用 Java 中的標記(annotation)而不是利用子類反射或命名機制來識別測試從而簡化測試在本文中執著的代碼測試人員 Elliotte Harold 以 JUnit 為例詳細介紹了如何在自己的工作中使用這個新框架注意本文假設讀者具有 JUnit 的使用經驗
  
  JUnit 由 Kent Beck 和 Erich Gamma 開發幾乎毫無疑問是迄今所開發的最重要的第三方 Java 庫正如 Martin Fowler 所說在軟件開發領域從來就沒有如此少的代碼起到了如此重要的作用JUnit 引導並促進了測試的盛行由於 JUnitJava 代碼變得更健壯更可靠bug 也比以前更少JUnit(它本身的靈感來自 Smalltalk 的 SUnit)衍生了許多 xUnit 工具將單元測試的優勢應用於各種語言nUnit (NET)pyUnit (Python)CppUnit (C++)dUnit (Delphi) 以及其他工具影響了各種平台和語言上的程序員的測試工作
  
  然而JUnit 僅僅是一個工具而已真正的優勢來自於 JUnit 所采用的思想和技術而不是框架本身單元測試測試先行的編程和測試驅動的開發並非都要在 JUnit 中實現任何比較 GUI 的編程都必須用 Swing 來完成JUnit 本身的最後一次更新差不多是三年以前了盡管它被證明比大多數框架更健壯更持久但是也發現了 bug而更重要的是Java 不斷在發展Java 語言現在支持泛型枚舉可變長度參數列表和注釋這些特性為可重用的框架設計帶來了新的可能
  
  JUnit 的停滯不前並沒有被那些想要廢棄它的程序員所打敗挑戰者包括 Bill Venners 的 Artima SuiteRunner 以及 Cedric Beust 的 TestNG 等這些庫有一些可圈可點的特性但是都沒有達到 JUnit 的知名度和市場占有份額它們都沒有在諸如 AntMaven 或 Eclipse 之類的產品中具有廣泛的開箱即用支持所以 Beck 和 Gamma 著手開發了一個新版本的 JUnit它利用 Java 的新特性(尤其是注釋)的優勢使得單元測試比起用最初的 JUnit 來說更加簡單用 Beck 的話來說JUnit 的主題是通過進一步簡化 JUnit鼓勵更多的開發人員編寫更多的測試JUnit 盡管保持了與現有 JUnit 測試套件的向後兼容但是它仍然承諾是自 JUnit 以來 Java 單元測試方面最重大的改進
  
  注意該框架的改進是相當前沿的盡管 JUnit 的大輪廓很清晰但是其細節仍然可以改變這意味著本文是對 JUnit 搶先看而不是它的最終效果
  
  測試方法
  
  以前所有版本的 JUnit 都使用命名約定和反射來定位測試例如下面的代碼測試 + 等於
  
  import junitframeworkTestCase;
  
  public class AdditionTest extends TestCase {
  
  private int x = ;
  private int y = ;
  
  public void testAddition() {
  int z = x + y;
  assertEquals( z);
  }
  
  }
  
  而在 JUnit 測試是由 @Test 注釋來識別的如下所示
  
  import orgjunitTest;
  import junitframeworkTestCase;
  
  public class AdditionTest extends TestCase {
  
  private int x = ;
  private int y = ;
  
  @Test public void testAddition() {
  int z = x + y;
  assertEquals( z);
  }
  
  }
  
  使用注釋的優點是不再需要將所有的方法命名為 testFoo()testBar()等等例如下面的方法也可以工作
  
  import orgjunitTest;
  import junitframeworkTestCase;
  
  public class AdditionTest extends TestCase {
  
  private int x = ;
  private int y = ;
  
  @Test public void additionTest() {
  int z = x + y;
  assertEquals( z);
  }
  
  }
  
  下面這個方法也同樣能夠工作
  
  import orgjunitTest;
  import junitframeworkTestCase;
  
  public class AdditionTest extends TestCase {
  
  private int x = ;
  private int y = ;
  
  @Test public void addition() {
  int z = x + y;
  assertEquals( z);
  }
  
  }
  
  這允許您遵循最適合您的應用程序的命名約定例如我介紹的一些例子采用的約定是測試類對其測試方法使用與被測試的類相同的名稱例如ntains() 由 ntains() 測試Listadd() 由 ListTestaddAll() 測試等等
  
  TestCase 類仍然可以工作但是您不再需要擴展它了只要您用 @Test 來注釋測試方法就可以將測試方法放到任何類中但是您需要導入 junitAssert 類以訪問各種 assert 方法如下所示
  
  import orgjunitAssert;
  
  public class AdditionTest {
  
  private int x = ;
  private int y = ;
  
  @Test public void addition() {
  int z = x + y;
  AssertassertEquals( z);
  }
  
  }
  
  您也可以使用 JDK 中新特性(static import)使得與以前版本一樣簡單
  
  import static orgjunitAssertassertEquals;
  
  public class AdditionTest {
  
  private int x = ;
  private int y = ;
  
  @Test public void addition() {
  int z = x + y;
  assertEquals( z);
  }
  
  }
  
  這種方法使得測試受保護的方法非常容易因為測試案例類現在可以擴展包含受保護方法的類了
  
  SetUp 和 TearDown
  
  JUnit 測試運行程序(test runner)會在運行每個測試之前自動調用 setUp() 方法該方法一般會初始化字段打開日志記錄重置環境變量等等例如下面是摘自 XOM 的 XSLTransformTest 中的 setUp() 方法
  
  protected void setUp() {
  
  SystemsetErr(new PrintStream(new ByteArrayOutputStream()));
  
  inputDir = new File(data);
  inputDir = new File(inputDir xslt);
  inputDir = new File(inputDir input);
  
  }
  
  在 JUnit 您仍然可以在每個測試方法運行之前初始化字段和配置環境然而完成這些操作的方法不再需要叫做 setUp()只要用 @Before 注釋來指示即可如下所示
  
  @Before protected void initialize() {
  
  SystemsetErr(new PrintStream(new ByteArrayOutputStream()));
  
  inputDir = new File(data);
  inputDir = new File(inputDir xslt);
  inputDir = new File(inputDir input);
  
  }
  
  甚至可以用 @Before 來注釋多個方法這些方法都在每個測試之前運行
  
  @Before protected void findTestDataDirectory() {
  inputDir = new File(data);
  inputDir = new File(inputDir xslt);
  inputDir = new File(inputDir input);
  }
  
  @Before protected void redirectStderr() {
  SystemsetErr(new PrintStream(new ByteArrayOutputStream()));
  }
  
  清除方法與此類似在 JUnit 您使用 tearDown() 方法該方法類似於我在 XOM 中為消耗大量內存的測試所使用的方法
  
  protected void tearDown() {
  doc = null;
  Systemgc();
  }
  
  對於 JUnit 我可以給它取一個更自然的名稱並用 @After 注釋它
  
  @After protected void disposeDocument() {
  doc = null;
  Systemgc();
  }
  
  與 @Before 一樣也可以用 @After 來注釋多個清除方法這些方法都在每個測試之後運行
  
  最後您不再需要在超類中顯式調用初始化和清除方法只要它們不被覆蓋即可測試運行程序將根據需要自動為您調用這些方法超類中的 @Before 方法在子類中的 @Before 方法之前被調用(這反映了構造函數調用的順序)@After 方法以反方向運行子類中的方法在超類中的方法之前被調用否則多個 @Before 或 @After 方法的相對順序就得不到保證
  
  套件范圍的初始化
  
  JUnit 也引入了一個 JUnit 中沒有的新特性類范圍的 setUp() 和 tearDown() 方法任何用 @BeforeClass 注釋的方法都將在該類中的測試方法運行之前剛好運行一次而任何用 @AfterClass 注釋的方法都將在該類中的所有測試都運行之後剛好運行一次
  
  例如假設類中的每個測試都使用一個數據庫連接一個網絡連接一個非常大的數據結構或者還有一些對於初始化和事情安排來說比較昂貴的其他資源不要在每個測試之前都重新創建它您可以創建它一次並還原它一次該方法將使得有些測試案例運行起來快得多例如當我測試調用第三方庫的代碼中的錯誤處理時我通常喜歡在測試開始之前重定向 Systemerr以便輸出不被預期的錯誤消息打亂然後我在測試結束後還原它如下所示
  
  // This class tests a lot of error conditions which
  // Xalan annoyingly logs to Systemerr This hides Systemerr
  // before each test and rest
From:http://tw.wingwit.com/Article/program/Java/ky/201311/28884.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.