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

JUnit實施

2013-11-23 20:39:03  來源: Java開源技術 

  測試的概念
  回歸測試框架JUnit
  Design by Contract
  Refactoring
  IDE對JUnit的支持
  JUnit簡介
  安裝
  Fixture
  TestCase
  TestSuite
  TestRunner
  JUnit最佳實踐
  JUnit與JEE
  測試的概念
   長期以來我所接觸的軟件開發人員很少有人能在開發的過程中進行測試工作大部分的項目都是在最終驗收的時候編寫測試文檔有些項目甚至沒有測試文檔現在情況有了改變我們一直提倡UMLRUP軟件工程CMM目的只有一個提高軟件編寫的質量舉一個極端的例子如果你是一個超級程序設計師一個傳奇般的人物(你可以一邊喝咖啡一邊聽著音樂同時編寫這操作系統中關於進程調度的模塊而且兩天時間內就完成了!)我真得承認有這樣的人(那個編寫UNIX中的vi編輯器的家伙就是這種人)然而非常遺憾的是這些神仙們並沒有留下如何修成正果的README所以我們這些凡人--在同一時間只能將注意力集中到若干點(據科學統計我並不太相信一般的人只能同時考慮最多個左右的問題高手可以達到個左右)而不能既縱覽全局又了解細節--只能期望於其他的方式來保證我們所編寫的軟件質量
   為了說明我們這些凡人是如何的笨有一個聰明人提出了軟件熵(software entropy)的概念一個程序從設計很好的狀態開始隨著新的功能不斷地加入程序逐漸地失去了原有的結構最終變成了一團亂麻你可能會爭辯在這個例子中設計很好的狀態實際上並不好如果好的話就不會發生你所說的情況是的看來你變聰明了可惜你還應該注意到兩個問題)我們不能指望在恐龍紀元(大概是十年前)設計的結構到了現在也能適用吧)擁有簽字權的客戶代表可不理會加入一個新功能是否會對軟件的結構有什麼影響即便有影響也是程序設計人員需要考慮的問題如果你拒絕加入這個你認為致命的新功能那麼你很可能就失去了你的住房貸款和面包(對中國工程師來說也許是米飯或面條要看你是南方人還是北方人)
   另外需要說明的是我看過的一些講解測試的書都沒有我寫的這麼有人情味(不好意思我希望看到這片文章的兄弟姐妹能很容易地接受測試的概念並付諸實施所以有些地方寫的有些誇張歡迎對測試有深入理解的兄弟姐妹能體察民情並不吝賜教
   好了我們現在言歸正傳要測試就要明白測試的目的我認為測試的目的很簡單也極具吸引力寫出高質量的軟件並解決軟件熵這一問題想象一下如果你寫的軟件和Richard Stallman(GNUFSF的頭兒)寫的一樣有水准的話是不是很有成就感?如果你一致保持這種高水准我保證你的薪水也會有所變動
   測試也分類白箱測試黑箱測試單元測試集成測試功能測試我們先不管有多少分類如何分類先看那些對我們有用的分類關於其他的測試有興趣的人可參閱其他資料白箱測試是指在知道被測試的軟件如何(How)完成功能和完成什麼樣(What)的功能的條件下所作的測試一般是由開發人員完成因為開發人員最了解自己編寫的軟件本文也是以白箱測試為主黑箱測試則是指在知道被測試的軟件完成什麼樣(What)的功能的條件下所作的測試一般是由測試人員完成黑箱測試不是我們的重點本文主要集中在單元測試上單元測試是一種白箱測試目的是驗證一個或若干個類是否按所設計的那樣正常工作集成測試則是驗證所有的類是否能互相配合協同完成特定的任務目前我們暫不關心它下面我所提到的測試除非特別說明一般都是指單元測試
   需要強調的是測試是一個持續的過程也就是說測試貫穿與開發的整個過程中單元測試尤其適合於迭代增量式(iterative and incremental)的開發過程Martin Fowler(有點兒像引用孔夫子的話)甚至認為在你不知道如何測試代碼之前就不應該編寫程序而一旦你完成了程序測試代碼也應該完成除非測試成功你不能認為你編寫出了可以工作的程序我並不指望所有的開發人員都能有如此高的覺悟這種層次也不是一蹴而就的但我們一旦了解測試的目的和好處自然會堅持在開發過程中引入測試 因為我們是測試新手我們也不理會那些復雜的測試原理先說一說最簡單的:測試就是比較預期的結果是否與實際執行的結果一致如果一致則通過否則失敗看下面的例子
  
  //將要被測試的類
  public class Car{
  public int getWheels() {
  return ;
  }
  }
  
  //執行測試的類
  public class testCar {
  public static void main(String[] args) {
  testCar myTest = new testCar();
  myTesttestGetWheels();
  }
  
  public testGetWheels () {
  int expectedWheels = ;
  Car myCar = Car();
  if (expectedWheels==myCargetWheels())
  Systemoutprintln(test [Car]: getWheels works perfected!);
  else
  Systemoutprintln(test [Car]: getWheels DOESNT work!);
  }
  }
  
   如果你立即動手寫了上面的代碼你會發現兩個問題第一如果你要執行測試的類testCar你必須必須手工敲入如下命令
  
  [Windows] d:>java testCar
  [Unix] % java testCar
  
   即便測試如例示的那樣簡單你也有可能不願在每次測試的時候都敲入上面的命令而希望在某個集成環境中(IDE)點擊一下鼠標就能執行測試後面的章節會介紹到這些問題第二如果沒有一定的規范測試類的編寫將會成為另一個需要定義的標准沒有人希望查看別人是如何設計測試類的如果每個人都有不同的設計測試類的方法光維護被測試的類就夠煩了誰還顧得上維護測試類?另外有一點我不想提但是這個問題太明顯了測試類的代碼多於被測試的類!這是否意味這雙倍的工作?不!)不論被測試類-Car
   的 getWheels 方法如何復雜測試類-testCar 的testGetWheels
   方法只會保持一樣的代碼量)提高軟件的質量並解決軟件熵這一問題並不是沒有代價的testCar就是代價
   我們目前所能做的就是盡量降低所付出的代價我們編寫的測試代碼要能被維護人員容易的讀取我們編寫測試代碼要有一定的規范最好IDE工具可以支持這些規范好了你所需要的就是JUnit一個Open Source的項目用其主頁上的話來說就是 JUnit是由 Erich Gamma 和 Kent Beck 編寫的一個回歸測試框架(regression testing framework)用於Java開發人員編寫單元測試之用所謂框架就是Erich Gamma 和 Kent Beck 定下了一些條條框框你編寫的測試代碼必須遵循這個條條框框繼承某個類實現某個接口其實也就是我們前面所說的規范好在JUnit目前得到了大多數軟件工程師的認可遵循JUnit我們會得到很多的支持回歸測試就是你不斷地對所編寫的代碼進行測試編寫一些測試一些調試一些然後循環這一過程你會不斷地重復先前的測試哪怕你正編寫其他的類由於軟件熵的存在你可能在編寫第五個類的時候發現第五個類的某個操作會導致第二個類的測試失敗通過回歸測試我們抓住了這條大Bug
  
  回歸測試框架JUnit
   通過前面的介紹我們對JUnit有了一個大概的輪廓知道了它是干什麼的現在讓我們動手改寫上面的測試類testCar使其符合Junit的規范--能在JUnit中運行
  
  //執行測試的類(JUnit版)
  import junitframework*;
  
  public class testCar extends TestCase {
  
  protected int expectedWheels;
  protected Car myCar;
  
  public testCar(String name) {
  super(name);
  }
  
  protected void setUp() {
  expectedWheels = ;
  myCar = new Car();
  }
  
  public static Test suite() {
  /*
  * the type safe way
  *
  TestSuite suite= new TestSuite();
  suiteaddTest(
  new testCar(CargetWheels) {
  protected void runTest() { testGetWheels(); }
  }
  );
  return suite;
  */
  
  /*
  * the dynamic way
  */
  return new TestSuite(testCarclass);
  }
  
  public void testGetWheels() {
  assertEquals(expectedWheels myCargetWheels());
  }
  }
  
   改版後的testCar已經面目全非先讓我們了解這些改動都是什麼含義再看如何執行這個測試
   >import語句引入JUnit的類(沒問題吧)
   >繼承 TestCase 可以暫時將一個TestCase看作是對某個類進行測試的方法的集合詳細介紹請參看JUnit資料
   >setUp()設定了進行初始化的任務我們以後會看到setUp會有特別的用處
   >testGetWheeels()對預期的值和myCargetWheels()返回的值進行比較並打印比較的結果assertEquals是junitframeworkAssert中所定義的方法junitframeworkTestCase繼承了junitframeworkAssert
   >suite()是一個很特殊的靜態方法JUnit的TestRunner會調用suite方法來確定有多少個測試可以執行上面的例子顯示了兩種方法靜態的方法是構造一個內部類並利用構造函數給該測試命名(test
   name 如 CargetWheels )其覆蓋的runTest()方法指明了該測試需要執行那些方法--testGetWheels()動態的方法是利用內省(reflection
   )來實現runTest()找出需要執行那些測試此時測試的名字即是測試方法(test method如testGetWheels)的名字JU
From:http://tw.wingwit.com/Article/program/Java/ky/201311/28831.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.