邊城愚人

          如果我不在邊城,我一定是在前往邊城的路上。

            BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
            31 隨筆 :: 0 文章 :: 96 評(píng)論 :: 0 Trackbacks

          ??? ??? 在做 Java 企業(yè)程序的時(shí)候,不可避免地要和外部資源打交道,比如數(shù)據(jù)庫(kù), Http 請(qǐng)求等。對(duì)于這些外部資源的處理,我們可采取的操作或者是直接處理或者是模擬處理。當(dāng)我們使用 Webwork Spring Hibernate 等框架時(shí),我們要測(cè)試的并不僅僅是 Java 代碼,我們還要測(cè)試依賴于這些框架的配置文件等等。因此,對(duì)于數(shù)據(jù)持久化的測(cè)試, Mock 方法是行不通的,我們需要真實(shí)地測(cè)試數(shù)據(jù)庫(kù)操作。對(duì)于持久化測(cè)試來說,重要的是創(chuàng)造出已知的“干凈的”的準(zhǔn)備數(shù)據(jù)。如果我們?cè)跍y(cè)試一個(gè)持久化方法前不能確定數(shù)據(jù)庫(kù)到底存著什么數(shù)據(jù),我們只能通過反復(fù)地查看數(shù)據(jù)庫(kù)數(shù)據(jù)來驗(yàn)證測(cè)試方法的正確性了(這就是我和大多數(shù)人以前使用的最“直接”的方法)。現(xiàn)在就讓我們使用 DbUnit ,來更好的更自動(dòng)化的測(cè)試持久化操作吧!

          ??? ??? 先介紹一下 DbUnit DbUnit 是一個(gè) JUnit 擴(kuò)展,適用于數(shù)據(jù)驅(qū)動(dòng)的程序。使用 DbUnit ,可以在測(cè)試運(yùn)行期間將數(shù)據(jù)庫(kù)的數(shù)據(jù)處于已知狀態(tài),這樣在測(cè)試時(shí)可以方便地寫出測(cè)試斷言,也能自動(dòng)地完成對(duì)數(shù)據(jù)持久化方法的測(cè)試。在使用上, DbUnit 也很簡(jiǎn)單, 它提供了大量的類對(duì)與數(shù)據(jù)庫(kù)相關(guān)的操作進(jìn)行了抽象和封裝,大多數(shù)情況下你只需要使用少量簡(jiǎn)單的 API

          ??? ??? 下面我通過一個(gè)實(shí)際的小例子,介紹一下如何使用 DbUnit 。我也是剛剛使用上了 DbUnit ,經(jīng)驗(yàn)上不是很豐富,如果文中有不對(duì)的地方,也歡迎指正。這個(gè)例子很簡(jiǎn)單,我將較為詳細(xì)地說明如何使用 Hibernate DbUnit 進(jìn)行測(cè)試。

          ??? ??? 測(cè)試第一步,準(zhǔn)備數(shù)據(jù)集。操作的數(shù)據(jù)表就是如下的 Account 表(使用的數(shù)據(jù)庫(kù)為Mysql):


          create ? table ?Account(
          ????id?
          bigint ? not ? null ?auto_increment,
          ????name?
          varchar ( 50 )? not ? null ,
          ????
          primary ? key (id)
          )
          character ? set ?gbk;

          ??? ??? 至于 Account 類,映射文件等這里就不給出了。AccountDAO 接口很簡(jiǎn)單,只有兩個(gè)方法:

          public ? interface ?AccountDAO?{
          ????
          void ?insert(Account?a);
          ????List
          < Account > ?findAll();
          }

          ???

          ??? ??? 實(shí)現(xiàn)類如下:

          public ? class ?AccountHibernateDAO? implements ?AccountDAO{
          ????
          ????
          public ? void ?insert(Account?a){
          ????????Session?s?
          = ?HibernateSessionFactory.getSession();
          ????????s.save(a);
          ????????s.close();
          ????}
          ????
          ????
          public ?List < Account > ?findAll(){
          ????????Session?s?
          = ??HibernateSessionFactory.getSession();
          ????????List
          < Account > ?l? = ?(List < Account > )s.createCriteria(Account. class ).list();
          ????????s.close();
          ????????
          return ?l;
          ????}
          }

          ??? ??? 在測(cè)試前,要準(zhǔn)備出數(shù)據(jù)表中要裝入的數(shù)據(jù)(也就是數(shù)據(jù)集),這里給出與Account表對(duì)應(yīng)的數(shù)據(jù)集文件 Accout.xml 內(nèi)容如下:


          <? xml?version='1.0'?encoding='UTF-8' ?>
          < dataset >
          ????
          < Account? id ="1" ?name ="kafka" />
          ????
          < Account? id ="2" ?name ="0102" />
          </ dataset >

          ? ??

          ??? ??? 數(shù)據(jù)集就是一個(gè) xml 文件, <dataset> 中的每個(gè)節(jié)點(diǎn)對(duì)應(yīng)的就是一條表數(shù)據(jù)記錄(一個(gè) dataset文件可以對(duì)應(yīng)多個(gè)數(shù)據(jù)表記錄 )。這里的 <Account> 節(jié)點(diǎn)對(duì)應(yīng)的就是 Account 表,屬性就是表中的字段,屬性值就是字段值了。在做測(cè)試時(shí),數(shù)據(jù)集中的內(nèi)容可以手動(dòng)敲進(jìn)去,也可以通過工具將數(shù)據(jù)庫(kù)中的數(shù)據(jù)導(dǎo)出來。 對(duì)于數(shù)據(jù)集的詳細(xì)信息,可參考 http://dbunit.sourceforge.net/components.html#FlatXmlDataSet
          ? ??

          ??? 測(cè)試第二步,擴(kuò)展 DBTestCase DBTestCase 是繼承自 JUnit 的類,擴(kuò)展它需要實(shí)現(xiàn) getDataSet() 來提供數(shù)據(jù)集。 另外,你也可以根據(jù)需要擴(kuò)展繼承于 DBTestCase 的子類 JdbcBasedDBTestCase DataSourceBasedDBTestCas JndiBasedDBTestCase 。下面是繼承于 DBTestCase AccountHibernateDAO 的測(cè)試類 AccountHibernateDAOTest

          package ?hibernatesample.dao.impl;
          import ?hibernatesample.domain.Account;
          import ?hibernatesample.util.HibernateSessionFactory;
          import ?java.io.File;
          import ?java.io.InputStream;
          import ?java.util.List;
          import ?org.dbunit.Assertion;
          import ?org.dbunit.DBTestCase;
          import ?org.dbunit.PropertiesBasedJdbcDatabaseTester;
          import ?org.dbunit.dataset.IDataSet;
          import ?org.dbunit.dataset.ITable;
          import ?org.dbunit.dataset.xml.FlatXmlDataSet;
          import ?org.dbunit.operation.DatabaseOperation;

          public ? class ?AccountHibernateDAOTest? extends ?DBTestCase?{

          ????
          private ?AccountHibernateDAO?accountDAO;
          ????
          ????
          public ?AccountHibernateDAOTest(){
          ????????System.setProperty(?PropertiesBasedJdbcDatabaseTester.DBUNIT_DRIVER_CLASS,?HibernateSessionFactory.getDriverClass());
          ???System.setProperty(?PropertiesBasedJdbcDatabaseTester.DBUNIT_CONNECTION_URL,?HibernateSessionFactory.getConnectionURL());
          ???System.setProperty(?PropertiesBasedJdbcDatabaseTester.DBUNIT_USERNAME,HibernateSessionFactory.getUsername());
          ???System.setProperty(?PropertiesBasedJdbcDatabaseTester.DBUNIT_PASSWORD,HibernateSessionFactory.getPassword());
          ????}
          ????
          ????@Override
          ????
          protected ?IDataSet?getDataSet()? throws ?Exception?{
          ????????String?path?
          = ? " hibernatesample " + File.separator + " dao " + File.separator + " dataset " + File.separator + " Account.xml " ;
          ????????InputStream?in?
          = ? this .getClass().getClassLoader().getResourceAsStream(path);
          ????????
          return ? new ?FlatXmlDataSet(in);
          ????}

          ????
          ????@Override
          ????
          protected ?DatabaseOperation?getSetUpOperation()? throws ?Exception?{
          ????????
          return ?DatabaseOperation.CLEAN_INSERT;
          ????}

          ????@Override
          ????
          protected ?DatabaseOperation?getTearDownOperation()? throws ?Exception?{
          ????????
          return ?DatabaseOperation.NONE;
          ????}

          ????
          protected ? void ?setUp()? throws ?Exception?{
          ????????
          super .setUp();
          ????????accountDAO?
          = ? new ?AccountHibernateDAO();
          ????}

          ????
          public ? void ?testInsert()?{
          ????????Account?a?
          = ? new ?Account();
          ????????a.setName(
          " aa " );
          ????????accountDAO.insert(a);
          ????????List
          < Account > ?l? = ?accountDAO.findAll();
          ????????assertEquals(
          3 ,?l.size());
          ????????Account?b?
          = ?l.get( 2 );
          ????????assertEquals(
          " aa " ,?b.getName());
          ????}

          ????
          public ? void ?testFindAll()?{
          ????????List
          < Account > ?l? = ?accountDAO.findAll();
          ????????assertEquals(
          2 ,?l.size());
          ????????Account?a?
          = ?l.get( 0 );
          ????????assertEquals(
          new ?Long( 1 ),?a.getId());
          ????????assertEquals(
          " kafka " ,?a.getName());
          ????????Account?b?
          = ?l.get( 1 );
          ????????assertEquals(
          new ?Long( 2 ),?b.getId());
          ????????assertEquals(
          " 0102 " ,?b.getName());
          ????}

          ????
          public ? void ?testDataset()? throws ?Exception?{
          ????????IDataSet?databaseDataSet?
          = ?getConnection().createDataSet();
          ????????ITable?actualTable?
          = ?databaseDataSet.getTable( " Account " );
          ????????IDataSet?expectedDataSet?
          = ?getDataSet();
          ????????ITable?expectedTable?
          = ?expectedDataSet.getTable( " Account " );
          ????????Assertion.assertEquals(expectedTable,?actualTable);
          ????}
          }

          ??? ??? 上面的DBTestCase 依賴于 IDatabaseTester 接口完成工作,而 PropertiesBasedJdbcDatabaseTester 就是其使用的默認(rèn)實(shí)現(xiàn), AccountHibernateDAOTest 構(gòu)造函數(shù)的作用是完成數(shù)據(jù)庫(kù)連接參數(shù)的設(shè)置。 protected IDataSet getDataSet() 實(shí)現(xiàn)了裝載數(shù)據(jù)集到 IDataSet 中。 getSetUpOperation getTearDownOperation 是可選的方法,返回的 DatabaseOperation DBTestCase SetUp TearDown 中將執(zhí)行的操作, getSetUpOperation 默認(rèn)的操作為 DatabaseOperation.CLEAN_INSERT ,也就是先清空數(shù)據(jù)表中的數(shù)據(jù)再插入數(shù)據(jù)集中的數(shù)據(jù)到數(shù)據(jù)表中。getTearDownOperation 默認(rèn)的操作為 DatabaseOperation.NONE ,就是什么也不處理。可選的操作還有幾個(gè),可參考文檔進(jìn)行設(shè)置,但默認(rèn)的設(shè)置是最通用的了。 testDataset ()只是測(cè)試數(shù)據(jù)集中的數(shù)據(jù)和裝載到數(shù)據(jù)庫(kù)中數(shù)據(jù)是否一致。

          ?? ??? 通過上面的設(shè)置,我們就可以測(cè)試dao方法的正確性了,而我們要做的只是準(zhǔn)備dataset文件及使用少量的DbUnit API(可以將這些操作寫到一個(gè)抽象類中,測(cè)試類都繼承自這個(gè)抽象類)。下一篇將介紹整合SpringHibernateDbUnit進(jìn)行測(cè)試。

          posted on 2007-06-14 09:03 kafka0102 閱讀(2777) 評(píng)論(2)  編輯  收藏 所屬分類: TDD

          評(píng)論

          # re: 使用DbUnit進(jìn)行持久化測(cè)試(1) 2007-06-14 09:19 kafka0102
          有誰知道如何在文章中附上文件?  回復(fù)  更多評(píng)論
            

          # re: 使用DbUnit進(jìn)行持久化測(cè)試(1) 2007-07-09 16:10 iamzzb
          @kafka0102
          在word中,選擇'插入'-'工具'-'對(duì)象'-'由文件創(chuàng)建'-'瀏覽'找到要出入的文件-'
          顯示為圖標(biāo)'-'確定'應(yīng)該是你要的效果吧  回復(fù)  更多評(píng)論
            


          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 同德县| 中超| 西峡县| 铁岭县| 天台县| 万安县| 安塞县| 汪清县| 临武县| 隆尧县| 交城县| 曲周县| 巴彦淖尔市| 安泽县| 靖安县| 化德县| 卓尼县| 游戏| 格尔木市| 察隅县| 岑溪市| 安宁市| 泰宁县| 秦皇岛市| 大英县| 东阳市| 砚山县| 西城区| 南投县| 鄢陵县| 林口县| 康定县| 阿拉善右旗| 怀安县| 兴安县| 三亚市| 阿图什市| 新绛县| 黑河市| 甘南县| 吉安市|