国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計 > 正文

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

2019-11-18 15:05:06
字體:
供稿:網(wǎng)友

  現(xiàn)實系統(tǒng)中通常會有一些具有外部依靠性的對象,這些對象和數(shù)據(jù)庫或者其他對象存在諸多關(guān)聯(lián)。假如我們對這樣的對象編寫單元和組件級測試的話,可以想象將是非常麻煩的一件事.因為這種外部依靠性的存在,使的我們很難將對象孤立出來進行測試。經(jīng)常提及的白盒測試法,基本上就是通過控制對象的外部依靠性來達到隔離對象的目的,使的可以操作這些對象的狀態(tài)和相關(guān)行為。
  
  運用 模擬對象(mock objects)
  或者stubs,就是一個控制對象外部依靠性的解決方案。通過隔離那些關(guān)聯(lián)的數(shù)據(jù)庫訪問類,象JDBC的相關(guān)操作類,對于控制對象外部依靠性將是很有效的。但模擬對象的解決方案對一些非凡的應(yīng)用系統(tǒng)架構(gòu)就顯得力不從心了,象那些運用了EJB的CMP(container-managed
  persistence)或者 JDO(java Data
  Objects)的應(yīng)用系統(tǒng)架構(gòu),在這些架構(gòu)里,數(shù)據(jù)庫的訪問對象是在最底層的而且很隱蔽。
  
  由Manuel Laflamme
  編寫的開放源代碼的DBUnit架構(gòu)體系,對于控制系統(tǒng)內(nèi)部的數(shù)據(jù)庫依靠性提供了一個非常不錯的解決方案。他答應(yīng)程序員在整個的測試過程中自由的治理控制數(shù)據(jù)庫的狀態(tài),這很重要。利用DBUnit,在測試之前,我們可以給目標數(shù)據(jù)庫植入我們需要的數(shù)據(jù)集,而且,在測試完畢后,數(shù)據(jù)庫完全能夠回溯到測試前的狀態(tài)。
  
  在很多成功的軟件項目中,測試自動化往往是要害的層面。DBUnit答應(yīng)開發(fā)人員創(chuàng)建測試用例代碼,在這些測試用例的生命周期內(nèi)我們可以很好的控制數(shù)據(jù)庫的狀態(tài)。而且,這些測試用例是很輕易實現(xiàn)自動化的。這樣在測試過程中我們無須對它進行人工的干預(yù),為人工干預(yù)造成的后果而擔(dān)心就更沒必要了。
  
  簡單介紹
  配置使用DBUnit的第一步我們首先需要知道如何生成數(shù)據(jù)庫schema,這個文件是xml格式的,其中包括了數(shù)據(jù)庫的表及相關(guān)數(shù)據(jù)信息。
  
  例如,這里有一個數(shù)據(jù)庫表employee
  ,我們可以用SQL的形式這樣將他表示出來。
  
  而且,我們可以看到,一個簡單的數(shù)據(jù)集可以這樣表示
  
  在DBUnit中,上面這個表和抽樣數(shù)據(jù)信息可以用XML文件的形式這樣表示:
  
  <EMPLOYEE employee_uid='1'
  start_date='2001-11-01'
  first_name='Andrew'
  ssn='xxx-xx-xxxx'
  last_name='Glover' />
  
  這個生成的XML格式的文件可以作為系統(tǒng)所需的所有種子文件(seed
  files)的樣本模版.
  
  為相互關(guān)聯(lián)的測試場景創(chuàng)建多個種子文件是一個很有效的策略,就象通過不同的數(shù)據(jù)庫文件來區(qū)分隔離數(shù)據(jù)庫狀態(tài)是一個道理。多種子文件策略可以將我們的測試目標鎖定到較小的范圍,目標數(shù)據(jù)可以只針對數(shù)據(jù)庫的表,而不是整個數(shù)據(jù)庫。
  
  為了給目標數(shù)據(jù)庫植入不同的職員記錄,我們需要的XML數(shù)據(jù)文件如下所示:
  <?xml version='1.0' encoding='UTF-8'?>
  
  <dataset>
  <EMPLOYEE employee_uid='1'
  start_date='2001-01-01'
  first_name='Drew' ssn='000-29-2030'
  last_name='Smith' />
  
  <EMPLOYEE employee_uid='2'
  start_date='2002-04-04'
  first_name='Nick' ssn='000-90-0000'
  last_name='Marquiss' />
  
  <EMPLOYEE employee_uid='3'
  start_date='2003-06-03'
  first_name='Jose' ssn='000-67-0000'
  last_name='Whitson' />
  </dataset>
  
  現(xiàn)在,要讓DBUnit和我們所需的數(shù)據(jù)庫schema一起工作了,對于程序員來說,我們使用DBUnit進行測試可以有兩種選擇:通過直接編碼方式進行測試或者與Ant結(jié)合.
  
  編碼方式
  DBUnit框架提供了一個基本的抽象測試用例類,叫做DatabaseTestCase,它是JUnit框架中的基礎(chǔ)類TestCase的子類。假如我們使用這個類必須首先實現(xiàn)兩個鉤子方法(hook
  methods):getConnection()和getDataSet().
  
  方法getConnection()需要返回一個IDatabaseConnection類型的對象,這個對象是一個基于普通JDBC連接的包裝類。例如,下面的代碼段演示了在MySQL數(shù)據(jù)庫環(huán)境下,IDatabaseConnection類型連接對象的創(chuàng)建方法。
  
  PRotected IDatabaseConnection getConnection()
  throws Exception {
  
  Class driverClass = Class.forName("org.gjt.mm.mysql.Driver");
  
  Connection jdbcConnection = DriverManager.getConnection(
  
  "jdbc:mysql://127.0.0.1/hr", "hr", "hr");
  
  return new DatabaseConnection(jdbcConnection);
  }
  
  方法getDataSet()返回一個IDataSet類型對象,其實,說白了,他就是我們先前提到的XML數(shù)據(jù)的種子文件的另一種表現(xiàn)形式。
  
  protected IDataSet getDataSet() throws Exception {
  return new FlatXmlDataSet(
  new
  FileInputStream("hr-seed.xml"));
  }
  
  有了這兩個基本的方法以后,DBUnit就可以按照它預(yù)先缺省的行為工作了。DatabaseTestCase類提供了兩個fixture(我叫它固件,不知仁兄同意否?)方法來控制測試前和測試后的數(shù)據(jù)庫狀態(tài)。這兩個方法就是:
  getSetUpOperation() 和 getTearDownOperation().
  
  一種高效的實施方案就是讓getSetUpOperation()方法執(zhí)行REFRESH操作,通過這個操作,我們可以用種子文件中的數(shù)據(jù)去更新目標數(shù)據(jù)庫里的數(shù)據(jù)。接下來,就是getTearDownOperation(),讓他去執(zhí)行一個NONE操作,也就是什么也不執(zhí)行。
  
  protected DatabaSEOperation getSetUpOperation()
  throws
  Exception {
  return DatabaseOperation.REFRESH;
  }
  
  protected DatabaseOperation getTearDownOperation()
  throws
  Exception {
  return DatabaseOperation.NONE;
  }
  
  還有一種有效的方法就是在getSetUpOperation()方法中執(zhí)行CLEAN_INSERT操作,這樣首先會將目標數(shù)據(jù)庫中與我們提供的種子文件一致的數(shù)據(jù)刪除,然后將我們提供的數(shù)據(jù)插入到數(shù)據(jù)庫中。這個實施順序保證了我們對數(shù)據(jù)庫的精確控制。
  
  代碼樣例
  在一個基于J2EE的人力資源系統(tǒng)中,我們很希望對某個數(shù)據(jù)操作周期實現(xiàn)測試自動化,這個操作周期包括職員的新增,檢索,更新和刪除。遠程接口定義了下列的業(yè)務(wù)方法(為了簡潔清楚,省略了方法中的throws子句).
  
  //譯者注:這里的EmployeeValueObject類型對象,譯者認為是代表職員實體信息的對象。
  
  public void  createEmployee( EmployeeValueObject emplVo )
  
  public EmployeeValueObject  getEmployeeBySocialSecNum( String ssn )
  
  public void  updateEmployee( EmployeeValueObject emplVo )
  
  public void  deleteEmployee( EmployeeValueObject emplVo )
  
  測試getEmployeeBySocialSecNum()方法
  需要植入一條數(shù)據(jù)到目標數(shù)據(jù)庫中,另外,測試deleteEmployee()方法和updateEmployee()方法時,同樣也是在先前植入的這條記錄的基礎(chǔ)上進行。最后,測試類會首先利用createEmployee()方法創(chuàng)建一條記錄,同時我們需要校驗執(zhí)行這個方法時,是否會有異常發(fā)生。
  
  下面這個DBUnit種子文件,叫做"employee_hr_seed.xml",下面將用到這個文件。
  
  <?xml version='1.0' encoding='UTF-8'?>
  <dataset>
  <EMPLOYEE employee_uid='1'
  start_date='2001-01-01'
  first_name='Drew' ssn='333-29-9999'
  last_name='Smith' />
  <EMPLOYEE employee_uid='2'
  start_date='2002-04-04'
  first_name='Nick' ssn='222-90-1111'
  last_name='Marquiss' />
  <EMPLOYEE employee_uid='3'
  start_date='2003-06-03'
  first_name='Jose' ssn='111-67-2222'
  last_name='Whitson' />
  </dataset>
  
  測試類 EmployeesessionFacadeTest
  ,需要擴展DBUnit的基礎(chǔ)類DatabaseTestCase并且必須提供對getConnection()和getDataSet()方法的實現(xiàn),在getConnection()方法中將獲得與EJB容器初始化時一樣的數(shù)據(jù)庫實例,getDataSet()方法負責(zé)讀取上面提及的employee_hr_seed.xml文件的數(shù)據(jù)。
  
  
  測試方法相當(dāng)簡單,因為DBUnit已經(jīng)為我們處理了復(fù)雜的數(shù)據(jù)庫生命周期任務(wù)。為了測試getEmployeeBySocialSecNum()方法,只需要簡單的傳遞一個存在于種子文件中的社保代碼號即可,比如
  "333-29-9999".
  
  //譯者注:EmployeeFacade 類型對象,譯者認為是代表底層數(shù)據(jù)庫數(shù)據(jù)的映射體
  
  public void testFindBySSN() throws Exception{
  
  EmployeeFacade facade = //oBTain somehow
  
  EmployeeValueObject vo =
  facade.getEmployeeBySocialSecNum("333-29-9999");
  
  TestCase.assertNotNull("vo shouldn't be null", vo);
  TestCase.assertEquals("should be Drew",
  "Drew", vo.getFirstName());
  TestCase.assertEquals("should be Smith",
  "Smith", vo.getLastName());
  }
  
  為了確保操作周期中的創(chuàng)建職員方法createEmployee()沒有問題,我們只需簡單的執(zhí)行一下這個方法,然后校驗一下看有沒有異常拋出,另外,下一步我們要做的就是在這條新增的記錄上進行查找操作,看是否可以找到剛創(chuàng)建的記錄。
  
  public void testEmployeeCreate() throws Exception{

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 稻城县| 兴宁市| 浦东新区| 新蔡县| 太仆寺旗| 固原市| 内江市| 高淳县| 寻甸| 赣州市| 汉沽区| 雷波县| 康马县| 宁强县| 开化县| 固安县| 开封县| 大新县| 长顺县| 崇信县| 武胜县| 瑞昌市| 河东区| 苗栗市| 浪卡子县| 深州市| 济阳县| 鄂托克前旗| 汕尾市| 聂拉木县| 介休市| 弋阳县| 敖汉旗| 芜湖县| 孝感市| 溧水县| 宜城市| 鸡东县| 玉田县| 寿宁县| 涪陵区|