隨筆-55  評論-208  文章-0  trackbacks-0

          記得我以前寫過一個文章是有關(guān)于4層web結(jié)構(gòu)單元測試的,今天打算對TDD的環(huán)境問題重新討論一下。

          我當時的4層結(jié)構(gòu)的單元測試時間上是從DAO到Service到Action再到JSP一種漸進測試,但是的想法是,先測DAO,那么Service對DAO的調(diào)用就有保證了,測試了Service,那么action調(diào)用service就有保證了。。。這樣一層一層下來,我每層測試的目標也就達到了。這里其實我用了一個技巧,就是通過測試的順序,來逐漸的構(gòu)建了每層測試所需的外部環(huán)境。當然從這個角度來看,我當時使用的方法更貼近于集成測試了。

          一般做TDD的時候最大的問題就是如何處理外部環(huán)境,這一般包括本身業(yè)務(wù)邏輯環(huán)境和技術(shù)框架環(huán)境。

          在當前這個新項目中,我首先嘗試對一個具體渲染器的測試方式就是用mock,這里用的是比較好用的easyMock。開始的時候覺得mock的方法很好用,但是當我發(fā)現(xiàn)我的待測方法中有多個需要mock的對象時(a.getX();b.getY();c.getZ())或者一個mock對象要通過多次級聯(lián)獲取時(如 a.getB().getC().getD().getE())就會發(fā)現(xiàn)mock的代價讓你高到很不原意mock的地步。

          而且當我們的框架卻制造了一個讓我無法逾越的障礙,就是我們對于manager(DAO)的調(diào)用都是用一個類的靜態(tài)方法封裝管理(比較奇怪為什么不用spring來進行管理呢)。這樣靜態(tài)方法就沒法mock了,于是乎,要想測試就要采用build的方法了,就是你可以在你的testCase中事先通過已經(jīng)實現(xiàn)好的DAO方法把需要使用到的業(yè)務(wù)對象真實的build出來,這樣你就可以知道你的被測方法中通過dao調(diào)用到的數(shù)據(jù)究竟是什么了,于是就可以對你期望獲得的結(jié)果和經(jīng)過實際方法得到的結(jié)果進行對比驗證了。
          看起來好像也是比較方便,但是實際上當你待測對象的業(yè)務(wù)模型,依賴于3-4級以上的相關(guān)模型時,你就會感覺到,這樣build是一個代價非常高的事情。這種代價通常會讓開發(fā)者喪失對TDD的興趣了。

          我發(fā)現(xiàn)其實在測試的時候我更加關(guān)注的是業(yè)務(wù)數(shù)據(jù)的build,而系統(tǒng)架構(gòu)通常是服務(wù)于業(yè)務(wù)的。所以我就開始考慮,能否有個方法構(gòu)建出最基本需要的業(yè)務(wù)模型數(shù)據(jù)呢。查閱了一些網(wǎng)上工具,發(fā)現(xiàn)沒有能夠滿足我當前需求(kodo做持久層,還有我們自己研發(fā)的知識引擎),于是就自己簡單做了一個InitialTestObject,想法很簡單就是通過一個xml文件然后根據(jù)已知的業(yè)務(wù)模型結(jié)構(gòu)定義好數(shù)據(jù),然后根據(jù)固定的規(guī)則初始化好業(yè)務(wù)數(shù)據(jù),并且存放到一個map中去(方法比較簡單我就不列出源碼了),然后再使用時把初始化放到setUp中去,這樣在測試的時候就可以根據(jù)你的需要直接從map中獲取到一個實際的業(yè)務(wù)對象用于測試的時候使用了,最后記得要在測試完成后要在tearDown中清除初始化的數(shù)據(jù)。這樣處理后我發(fā)現(xiàn)在測試時就感覺到很方便了,用到什么直接從map中取就可以了。

          也許有人會說這樣做不還是是集成測試了嗎,你build的時候需要數(shù)據(jù)庫、持久層啊什么的,這里我不想來爭論究竟是屬于單元測試還是集成測試,因為它屬于什么對于我們的功能來說是沒有意義。無論什么測試的最終目標就是讓我們的功能可用。

          至于構(gòu)建環(huán)境的實現(xiàn)我只是給出了一個對于我當前項目代價最小的方法,其實如果你的項目不是使用靜態(tài)方法的話,可以考慮構(gòu)建一個完全mock的環(huán)境這樣就可以稱之為單元測試了。
          而且對于這個InitialTestObject我覺得可以做成一個開源的小工具,支持各種不同的持久層(jdo,hibernate),然后根據(jù)我們定義的持久層模型做為我們的業(yè)務(wù)規(guī)則,就不需要自己編寫具體的初始化規(guī)則代碼了,你只需要寫xml數(shù)據(jù)并指定好對應(yīng)的持久層模型,希望大家可以對這個想法對提提建議,也許已經(jīng)有人做了,那我就不做重復(fù)功了。

          下篇預(yù)告:think in refactor         時間:待定


          鏈客中國,寫文章也可以賺錢哦
          posted on 2007-09-13 00:35 rocket 閱讀(1018) 評論(1)  編輯  收藏

          評論:
          # re: TDD:mock還是build [未登錄] 2007-09-13 19:29 | jack
          呵呵,這個想法不錯.
          其實有時候我們是需要真實數(shù)據(jù)測試的.
          所以先要提供一套接口就象我們的 JDBC 接口一樣.
          XML 只是要創(chuàng)建對象的一個描述(當然支持 IOC)
          然后默認先實現(xiàn) JDO,hibernate 的實現(xiàn).
          如果有其他需求的可以擴展接口!
          rocket 為社區(qū)做點貢獻吧!  回復(fù)  更多評論
            

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


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 鲜城| 恩平市| 若尔盖县| 永修县| 西青区| 拉萨市| 桑日县| 玉环县| 镇坪县| 正镶白旗| 枝江市| 海原县| 吴江市| 郑州市| 芒康县| 武强县| 长寿区| 封丘县| 淮阳县| 资中县| 通城县| 仪征市| 墨玉县| 石门县| 新沂市| 库尔勒市| 六盘水市| 沅江市| 泰来县| 贵港市| 岳阳市| 金乡县| 张北县| 京山县| 九寨沟县| 筠连县| 济南市| 淮阳县| 敦煌市| 阳西县| 巴东县|