熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> JSP教程 >> 正文

運用 DBUnit 進行高效的單元測試

2013-11-15 09:48:01  來源: JSP教程 

  現實系統中通常會有一些具有外部依賴性的對象這些對象和數據庫或者其他對象存在諸多關聯如果我們對這樣的對象編寫單元和組件級測試的話可以想象將是非常麻煩的一件事因為這種外部依賴性的存在使的我們很難將對象孤立出來進行測試經常提及的白盒測試法基本上就是通過控制對象的外部依賴性來達到隔離對象的目的使的可以操作這些對象的狀態和相關行為
  
  運用 模擬對象(mock objects)
  或者stubs就是一個控制對象外部依賴性的解決方案通過隔離那些關聯的數據庫訪問類象JDBC的相關操作類對於控制對象外部依賴性將是很有效的但模擬對象的解決方案對一些特殊的應用系統架構就顯得力不從心了象那些運用了EJB的CMP(containermanaged
  persistence)或者 JDO(java Data
  Objects)的應用系統架構在這些架構裡數據庫的訪問對象是在最底層的而且很隱蔽
  
  由Manuel Laflamme
  編寫的開放源代碼的DBUnit架構體系對於控制系統內部的數據庫依賴性提供了一個非常不錯的解決方案他允許程序員在整個的測試過程中自由的管理控制數據庫的狀態這很重要利用DBUnit在測試之前我們可以給目標數據庫植入我們需要的數據集而且在測試完畢後數據庫完全能夠回溯到測試前的狀態
  
  在很多成功的軟件項目中測試自動化往往是關鍵的層面DBUnit允許開發人員創建測試用例代碼在這些測試用例的生命周期內我們可以很好的控制數據庫的狀態而且這些測試用例是很容易實現自動化的這樣在測試過程中我們無須對它進行人工的干預為人工干預造成的後果而擔心就更沒必要了
  
  簡單介紹
  配置使用DBUnit的第一步我們首先需要知道如何生成數據庫schema這個文件是XML格式的其中包括了數據庫的表及相關數據信息
  
  例如這裡有一個數據庫表employee
  我們可以用SQL的形式這樣將他表示出來
  
  而且我們可以看到一個簡單的數據集可以這樣表示
  
  在DBUnit中上面這個表和抽樣數據信息可以用XML文件的形式這樣表示
  
  <EMPLOYEE employee_uid=
  start_date=
  first_name=Andrew
  ssn=xxxxxxxxx
  last_name=Glover />
  
  這個生成的XML格式的文件可以作為系統所需的所有種子文件(seed
  files)的樣本模版
  
  為相互關聯的測試場景創建多個種子文件是一個很有效的策略就象通過不同的數據庫文件來區分隔離數據庫狀態是一個道理多種子文件策略可以將我們的測試目標鎖定到較小的范圍目標數據可以只針對數據庫的表而不是整個數據庫
  
  為了給目標數據庫植入不同的職員記錄我們需要的XML數據文件如下所示
  <?xml version= encoding=UTF?>
  
  <dataset>
  <EMPLOYEE employee_uid=
  start_date=
  first_name=Drew ssn=
  last_name=Smith />
  
  <EMPLOYEE employee_uid=
  start_date=
  first_name=Nick ssn=
  last_name=Marquiss />
  
  <EMPLOYEE employee_uid=
  start_date=
  first_name=Jose ssn=
  last_name=Whitson />
  </dataset>
  
  現在要讓DBUnit和我們所需的數據庫schema一起工作了對於程序員來說我們使用DBUnit進行測試可以有兩種選擇通過直接編碼方式進行測試或者與Ant結合
  
  編碼方式
  DBUnit框架提供了一個基本的抽象測試用例類叫做DatabaseTestCase它是JUnit框架中的基礎類TestCase的子類如果我們使用這個類必須首先實現兩個鉤子方法(hook
  methods)getConnection()和getDataSet()
  
  方法getConnection()需要返回一個IDatabaseConnection類型的對象這個對象是一個基於普通JDBC連接的包裝類例如下面的代碼段演示了在MySQL數據庫環境下IDatabaseConnection類型連接對象的創建方法
  
  protected IDatabaseConnection getConnection()
  throws Exception {
  
  Class driverClass = ClassforName(orggjtmmmysqlDriver);
  
  Connection jdbcConnection = DriverManagergetConnection(
  
  jdbc:mysql:///hr hr hr);
  
  return new DatabaseConnection(jdbcConnection);
  }
  
  方法getDataSet()返回一個IDataSet類型對象其實說白了他就是我們先前提到的XML數據的種子文件的另一種表現形式
  
  protected IDataSet getDataSet() throws Exception {
  return new FlatXmlDataSet(
  new
  FileInputStream(hrseedxml));
  }
  
  有了這兩個基本的方法以後DBUnit就可以按照它預先缺省的行為工作了DatabaseTestCase類提供了兩個fixture(我叫它固件不知仁兄同意否?)方法來控制測試前和測試後的數據庫狀態這兩個方法就是
  getSetUpOperation() 和 getTearDownOperation()
  
  一種高效的實施方案就是讓getSetUpOperation()方法執行REFRESH操作通過這個操作我們可以用種子文件中的數據去更新目標數據庫裡的數據接下來就是getTearDownOperation()讓他去執行一個NONE操作也就是什麼也不執行
  
  protected DatabaseOperation getSetUpOperation()
  throws
  Exception {
  return DatabaseOperationREFRESH;
  }
  
  protected DatabaseOperation getTearDownOperation()
  throws
  Exception {
  return DatabaseOperationNONE;
  }
  
  還有一種有效的方法就是在getSetUpOperation()方法中執行CLEAN_INSERT操作這樣首先會將目標數據庫中與我們提供的種子文件一致的數據刪除然後將我們提供的數據插入到數據庫中這個實施順序保證了我們對數據庫的精確控制
  
  代碼樣例
  在一個基於JEE的人力資源系統中我們很希望對某個數據操作周期實現測試自動化這個操作周期包括職員的新增檢索更新和刪除遠程接口定義了下列的業務方法(為了簡潔清楚省略了方法中的throws子句)
  
  //譯者注這裡的EmployeeValueObject類型對象譯者認為是代表職員實體信息的對象
  
  public void  createEmployee( EmployeeValueObject emplVo )
  
  public EmployeeValueObject  getEmployeeBySocialSecNum( String ssn )
  
  public void  updateEmployee( EmployeeValueObject emplVo )
  
  public void  deleteEmployee( EmployeeValueObject emplVo )
  
  測試getEmployeeBySocialSecNum()方法
  需要植入一條數據到目標數據庫中另外測試deleteEmployee()方法和updateEmployee()方法時同樣也是在先前植入的這條記錄的基礎上進行最後測試類會首先利用createEmployee()方法創建一條記錄同時我們需要校驗執行這個方法時是否會有異常發生
  
  下面這個DBUnit種子文件叫做employee_hr_seedxml下面將用到這個文件
  
  <?xml version= encoding=UTF?>
  <dataset>
  <EMPLOYEE employee_uid=
  start_date=
  first_name=Drew ssn=
  last_name=Smith />
  <EMPLOYEE employee_uid=
  start_date=
  first_name=Nick ssn=
  last_name=Marquiss />
  <EMPLOYEE employee_uid=
  start_date=
  first_name=Jose ssn=
  last_name=Whitson />
  </dataset>
  
  測試類 EmployeeSessionFacadeTest
  需要擴展DBUnit的基礎類DatabaseTestCase並且必須提供對getConnection()和getDataSet()方法的實現在getConnection()方法中將獲得與EJB容器初始化時一樣的數據庫實例getDataSet()方法負責讀取上面提及的employee_hr_seedxml文件的數據
  
  
  測試方法相當簡單因為DBUnit已經為我們處理了復雜的數據庫生命周期任務為了測試getEmployeeBySocialSecNum()方法只需要簡單的傳遞一個存在於種子文件中的社保代碼號即可比如
  
  
  //譯者注EmployeeFacade 類型對象譯者認為是代表底層數據庫數據的映射體
  
  public void testFindBySSN() throws Exception{
  
  EmployeeFacade facade = //obtain somehow
  
  EmployeeValueObject vo =
  facadegetEmployeeBySocialSecNum();
  
  TestCaseassertNotNull(vo shouldnt be null vo);
  TestCaseassertEquals(should be Drew
  Drew vogetFirstName());
  TestCaseassertEquals(should be Smith
  Smith vogetLastName());
  }
  
  為了確保操作周期中的創建職員方法createEmployee()沒有問題我們只需簡單的執行一下這個方法然後校驗一下看有沒有異常拋出另外下一步我們要做的就是在這條新增的記錄上進行查找操作看是否可以找到剛創建的記錄
  
  public void testEmployeeCreate() throws Exception{

From:http://tw.wingwit.com/Article/program/Java/JSP/201311/19133.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.