常用鏈接

          統計

          最新評論

          JUnit 學習筆記 2007版(轉)

          一、簡介
              JUnit是一款由Erich Gamma(《設計模式》的作者)和Kent Beck(極限編程的提出者)編寫的開源的回歸測試框架,供Java編碼人員做單元測試之用。當前版本4.1,可以從www.junit.org網站上獲得。與早期的JUnit 3相比,JUnit 4.1依賴于Java 5.0的新特性,因此無法兼容于jdk 1.4,可以說是一個全新的框架。
              由于這里使用的IDE是Eclipse 3.2.1加語言包,已經集成了junit 4.1,因此便免去下載和配置類庫的麻煩了^_^
          二、創建項目
              下面打開Eclipse,點擊菜單“文件”->“新建”->“項目”或“新建”按鈕,打開“新建”對話框:
          請選中“Java項目”,點擊“下一步”,進入“新建Java項目”對話框:
          在這個對話框中需要設置項目的名稱以及項目所在目錄,我為自己的項目起名為JUnitTest,目錄為F:\YPJCCK\JUnit\Eclipse\JUnitTest。由于Eclipse自帶了JUnit類庫,因此此時點擊“完成”即可。
          三、編寫用于測試的JavaBean
              用于測試的JavaBean很簡單,名為Book,只有id和name兩個屬性,這兩個屬性將分別用于兩個用例當中。下面開始編寫該JavaBean。
              請點擊“文件”->“新建”->“類”,打開“新建Java類”對話框,設置包為net.test.unit.junit,名稱為Book,并確保“public static void main(String[] args)”選項沒有選中,然后點擊“完成”。修改代碼如下:
          package net.test.unit.junit;
              
          public class Book {
              
                  private String id = null;
                  private String name = null;
              
                  public String getId() {
                      return id;
                  }
              
                  public void setId(String id) {
                      this.id = id;
                  }
              
                  public String getName() {
                      return name;
                  }
              
                  publicvoid setName(String name) {
                      this.name = name;
                  }
              
          }
          至此,用于測試的JavaBean編寫完成。
          四、編寫測試用例
              這里只用了一個類進行測試,名為BookTest。以前像這樣的類是需要繼承junit.framework.TestCase的,但由于JUnit 4.1充分利用了Java 5.0新增的注解功能,因此便無須再這樣做了。當然,JUnit 4.1仍然提供對舊方式的支持,不過這里并不打算介紹。
              BookTest類包含兩個用例,分別對應該類的caseId和caseName方法,即每個方法實現一個用例。與JUnit 3.8.1不同,在JUnit 4.1中不再強制要求方法名以test開頭,而是允許隨意命名,只要符合Java的命名規范就行,這里為了表明這點,特意用了case開頭,但測試用例必須以@Test注解。此外,BookTest還有setUp和tearDown這兩個方法,并分別使用@Before和@After來進行注解,前者在每個測試方法開始之前執行,多用來做初始化;后者在每個測試方法完成之后執行,多用來清理資源。注意,這兩個方法的命名同樣沒有限制,且定義的數量也沒有限制,只是必須用@Before和@After進行注解。另外,JUnit 4.1還提供了@BeforeClass和@AfterClass注解,功能與@Before和@After類似,但前者是用在所有用例執行之前做初始化、之后做清理,而后者是在每個用例執行之前做初始化、之后做清理。下面開始編寫BookTest。
              在Eclipse中,創建BookTest類有兩種方法:方法一,像前邊創建Book類一樣,點擊“文件”->“新建”->“類”來創建;方法二,先在“包資源管理器”中選中Book類,然后點擊“文件”->“新建”->“JUnit測試用例”,打開“新建JUint測試用例”窗口:
          此時會發現,很多信息已經被Eclipse自動添加進來了。如果想利用Eclipse自動創建測試方法,請點擊“下一步”。由于本文會自行編寫測試方法,因此請直接點擊“完成”。
              創建BookTest類后,修改代碼如下:
          package net.test.unit.junit;
              
          import static org.junit.Assert.*;
              
          import org.junit.After;
          import org.junit.Before;
          import org.junit.Test;
              
          public class BookTest {
              
                  Book book = null;
              
                  @Before
                  public void setUp() throws Exception {
                      System.out.println("測試開始!");
                      book = new Book();
                      System.out.println("book對象被初始化!");
                  }
              
                  @After
                  public void tearDown() throws Exception {
                      System.out.println("book對象將被清理!");
                      book = null;
                      System.out.println("測試結束!");
                  }
              
                  @Test
                  public void caseId() {
                      book.setId("001"); //設置id屬性的值為001
                      //使用Assert查看id屬性的值是否為001
                      assertEquals("001", book.getId());
                      System.out.println("id屬性被測試!");
                  }
              
                  @Test
                  public void caseName() {
                      book.setName("ASP"); //設置name屬性的值為ASP
                      //使用Assert查看name屬性的值是否為JSP,這是個必然出現錯誤的測試
                      assertEquals("JSP", book.getName());
                      System.out.println("name屬性被測試!");
                  }
                  
          }
          這里setUp和tearDown方法沒什么好說的,就是執行了對book對象的初始化和清理,不過caseId和caseName需要說明一下。前者是在對book的id屬性進行測試,首先賦值為”001”,然后使用assertEquals方法查看id屬性中存放的值是否是期待的值,由于我的期待值也是”001”,所以執行后這個用例應該是成功的;后者則是對book的name屬性進行測試,也是首先賦值為”ASP”,然后使用assertEquals方法查看其值是否是期待的,由于我特意將期待值設定為根本不可能的”JSP”,因此這個用例執行后會出現一個錯誤。
          關于assertEquals方法,是Assert類的一個靜態方法。在程序開頭有這樣一行代碼,“import static org.junit.Assert.*;”,利用了Java 5.0提供的靜態導入將Assert類靜態導入,因此我們在程序中可以直接使用Assert類的任何靜態方法。下面簡單介紹一下靜態類org.junit.Assert。
          該類主要包含8類22個方法,如下:
              1.assertEquals(),8個重載,用來查看對象中存的值是否是期待的值,與字符串比較中使用的equals()方法類似;
              2.assertFalse()和assertTrue(),各2個重載,用來查看變量是是否為false或true,如果assertFalse()查看的變量的值是false則測試成功,如果是true則失敗,assertTrue()與之相反;
              3.assertSame()和assertNotSame(),各2個重載,用來比較兩個對象的引用是否相等和不相等,類似于通過“==”和“!=”比較兩個對象;
              4.assertNull()和assertNotNull(),各2個重載,用來查看對象是否為空和不為空;
              5.fail (),2個重載,意為失敗,用來拋出錯誤。我個人認為有兩個用途:首先是在測試驅動開發中,由于測試用例都是在被測試的類之前編寫,而寫成時又不清楚其正確與否,此時就可以使用fail方法拋出錯誤進行模擬;其次是拋出意外的錯誤,比如要測試的內容是從數據庫中讀取的數據是否正確,而導致錯誤的原因卻是數據庫連接失敗。
          五、運行BookTest
              編寫好BookTest后,就可以運行了。請點擊運行按鈕旁邊的倒三角,選擇“運行為”->“1 JUnit測試”,此時運行效果如下圖:
          在圖片的左側可以看到“JUnit”一欄,而且里邊還有一個錯誤。不過這個錯誤是預計之內的,如果不想看到,可以將testName()方法中的”JSP”改成”ASP”,此時的運行效果如下圖:
          此時您會看到,“JUnit”欄中的進度條已不是紅色,而是綠色的,這說明已經沒有錯誤了。
          六、測試套件
              當有多個測試類需要同時進行測試時,應使用測試套件來完成該工作。但Eclipse 3.2.1所提供的測試套件創建功能無法很好地支持JUnit 4.1,所以我們只能手工來創建了。
              點擊“文件”->“新建”->“類”創建一個類,類名為AllTests,如下圖:
          點擊“完成”,修改代碼如下:
          package net.test.unit.junit;
              
          import org.junit.runner.RunWith;
          import org.junit.runners.Suite;
              
          @RunWith(Suite.class)
          @Suite.SuiteClasses(BookTest.class)
          public class AllTests {}
          這里空類AllTests使用@RunWith和@Suite.SuiteClasses進行注解,以作為測試程序入口。將要測試的類BookTest作為@Suite.SuiteClasses注解的參數,然后將測試套件Suite作為參數設置給運行器@RunWith。下面就可以選中該文件,點擊“運行為”->“1 JUnit測試”了。
              這里注意一點,@Suite.SuiteClasses注解支持數組,例如:
                  @Suite.SuiteClasses ({BookTest.class, BookTest2.class })
          這樣就可以一次運行多個測試類了。
          七、命令行下
              前邊介紹的運行方式都是基于Eclipse的,其實JUnit自身也提供了辦法,可以在命令行下執行如下命令:
              java -cp junit-4.1.jar所在文件夾; org.junit.runner.JUnitCore
          net.test.unit.junit.AllTests
          如果要運行多個測試類,如下:
              java -cp junit-4.1.jar所在文件夾; org.junit.runner.JUnitCore
          net.test.unit.junit.AllTests net.test.unit.BookTest
          八、JUnit使用進階
              @Ignore注解,忽略測試,用于忽略暫時不想運行的測試用例。以BookTest為例,在文件頭部添加引用“import org.junit.Ignore;”,然后修改caseName方法:
          @Ignore
          @Test
              public void caseName()
          點擊“運行為”->“1 JUnit測試”,運行效果如下:
          此時caseName()方法已經被忽略了。
              @Test注解的expected參數,異常測試,用于測試是否會拋出指定的異常,若拋出則為成功,反之為失敗。請在BookTest中新增一個測試用例:
              @Test(expected = ArithmeticException.class)
              public void caseException() {
                  int n = 2 / 0;
              }
          這個測試用例是以0為除數,運行效果如下:
          成功!因為指定的ArithmeticException異常被拋出了。
              @Test注解的timeout參數,限時測試,用于限定測試用例耗費的時間,單位毫秒,如果測試用例沒有在限定時間內完成則為失敗,否則以測試用例的執行結果為準。請在BookTest中新增一個測試用例:
          @Test(timeout=1000)
              public void caseWhile() {
                  for (;;) {
                  }
          }
          這是一個死循環,1秒之后將被強制停止,運行效果如下:
          由于超時,運行失敗。
              @Parameters注解,參數化測試,用于對同一測試用例測試一組數據。請新建一個“JUnit測試用例”BookTest2,修改代碼如下:
          package net.test.unit.junit;
             
          import static org.junit.Assert.assertEquals;
             
          import java.util.Arrays;
          import java.util.Collection;
             
          import org.junit.After;
          import org.junit.Before;
          import org.junit.Test;
          import org.junit.runner.RunWith;
          import org.junit.runners.Parameterized;
          import org.junit.runners.Parameterized.Parameters;
             
          @RunWith(Parameterized.class)
          public class BookTest2 {
             
                  private String expectedId;
                  private String targetId;
                  private String expectedName;
                  private String targetName;
             
                  Book book = null;
             
                  @Parameters
                  public static Collection Result() {
                      return Arrays.asList(new Object[][] {
                          { "002", "001", "JSP", "ASP" },
                          { "001", "001", "ASP", "ASP" }
                          });
                  }
             
                  public BookTest2(String expectedId, String targetId, String expectedName, String targetName) {
                      this.expectedId = expectedId;
                      this.targetId = targetId;
                      this.expectedName = expectedName;
                      this.targetName = targetName;
                  }
             
                  @Before
                  public void setUp() throws Exception {
                      System.out.println("測試開始!");
                       book = new Book();
                       System.out.println("book對象被初始化!");
                  }
             
                  @After
                  public void tearDown() throws Exception {
                      System.out.println("book對象將被清理!");
                       book = null;
                       System.out.println("測試結束!");
                  }
             
                  @Test
                  public void caseId() {
                      book.setId(targetId); //設置id屬性的值
                       //使用Assert查看id屬性的值
                       assertEquals(expectedId, book.getId());
                       System.out.println("id屬性被測試!");
                  }
             
                  @Test
                  public void caseNames() {
                      book.setName(targetName); //設置name屬性的值
                       //使用Assert查看name屬性的值
                       assertEquals(expectedName, book.getName());
                       System.out.println("name屬性被測試!");
                  }
          }
          這個例子其實就是BookTest的擴展版,但在原基礎上有幾點變化:
          首先是文件頭部增加了一行代碼:@RunWith(Parameterized.class),用來調用BookTest2類運行;
          其次是定義了一個用@Parameters注解的Result靜態方法,該方法用來存放測試數據,本例存放了2組數據,每組4個;
          再次是定義了一個帶參數的構造函數,其參數個數與每組測試數據的個數相等;
              最后是定義了expectedId等4個成員變量,用來傳遞測試數據到測試用例中。
          下面執行BookTest2,運行效果如下:
          測試用例運行了兩遍,第一遍由于期待值和設定值不相等而失敗,第二遍則運行成功。
              junit.framework.JUnit4TestAdapter類。依賴于Java 5.0新特性,開發測試用例無需繼承junit.framework.TestCase的JUnit 4.1已經推出一段時間了,但有些自帶JUnit測試環境的IDE,例如NetBeans 5.5甚至舊版Eclipse仍只支持JUnit 3,無法正確運行基于JUnit 4.1環境開發的測試用例,因此要解決這個問題,需要借助于junit.framework.JUnit4TestAdapter類。新建類TestSuite,修改代碼如下:
          package net.test.unit.junit;
             
          public class TestSuite {
             
                  public staticvoid main(String[] args) {
                      junit.textui.TestRunner.run(TestSuite.suite());
                  }
             
                  public static junit.framework.Test suite() {
                      return new junit.framework.JUnit4TestAdapter(AllTests.class);   
                  }
          }
          其中最重要的是suite方法,該方法通過junit.framework.JUnit4TestAdapter類使基于JUnit 4環境創建的AllTests類能夠運行于JUnit 3命令行環境下。
          九、版本
          《JUnit學習筆記》,2005年7月24日,JUnit版本3.8.1,IDE為Eclipse 3.0.1和JBuilderX。
          《JUnit學習筆記(第二版)》,2006年1月27日,JUnit版本3.8.1,IDE為Eclipse 3.1.1和JBuilder 2006。
          十、參考
              《JUnit 4 搶先看》;
              《單元測試利器 JUnit 4》;
              《全面認識JUnit 4的新特征》;
              《新版JUnit 4.0 搶先體驗》;
              《JUnit重裝上陣》等。


          Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1531840

          posted on 2007-10-24 13:10 九寶 閱讀(456) 評論(0)  編輯  收藏 所屬分類: Java

          主站蜘蛛池模板: 县级市| 丰镇市| 惠安县| 乡城县| 宜昌市| 灵武市| 延寿县| 嵊泗县| 湘阴县| 邵阳市| 泰兴市| 玉环县| 阿克陶县| 德令哈市| 湘阴县| 五常市| 申扎县| 武汉市| 武清区| 永胜县| 西峡县| 镇宁| 定远县| 灌云县| 贡山| 沂南县| 台南市| 铁岭县| 阿克苏市| 烟台市| 凤凰县| 鹿泉市| 洛宁县| 特克斯县| 买车| 新和县| 丹凤县| 临桂县| 郧西县| 汉沽区| 蓝田县|