隨筆 - 4  文章 - 16  trackbacks - 0
          <2008年11月>
          2627282930311
          2345678
          9101112131415
          16171819202122
          23242526272829
          30123456

          常用鏈接

          留言簿(3)

          隨筆分類

          隨筆檔案

          文章分類

          新聞檔案

          好友

          最新隨筆

          搜索

          •  

          積分與排名

          • 積分 - 11217
          • 排名 - 2286

          最新評論

          閱讀排行榜

          評論排行榜

          本節(jié)是單元測試系列的第二篇。重點講解如何使用Mock/Stub和依賴注入技術(shù)進行單元測試。關(guān)于工具JUnit等則不做累贅介紹。 希望通過本章能夠幫助大家開始單元測試的有益實踐,與大家共勉!

          單元測試(技能篇)

          一、Stub技術(shù)

          這是最為古老的一種測試技能。通過類層次上的替換實現(xiàn)了對待測環(huán)境的模擬。

          實現(xiàn)的時候有兩種途徑:

          1、重寫實際類,在測試時,先于實際類加載,即覆蓋。如:我們在unittest/stub文件夾下針對于每一個重寫類都有相同的包結(jié)構(gòu)和類名:


          在類路徑中優(yōu)先加載:


          2、在實際代碼中添加判斷。比如,如果當前是測試環(huán)境if(isUT)執(zhí)行XX操作,截斷真正需要做的事。

              publicvoid sendCommand(int cmdCode)

              {

                 if(isUT())

                 {

                     //...

                 }

                 else

                 {

                     //...

                 }

              }

          Stub技術(shù)的問題就在于我們在重寫這些類的時候,不僅僅要關(guān)注接口,還要關(guān)注其內(nèi)部邏輯。如果你只是簡單的返回一個固定的響應(yīng),會很簡單。但是對于每一次運行需要根據(jù)不同的輸入返回不同的輸出時方法內(nèi)部的處理就會復(fù)雜的多。

          由于實現(xiàn)的難度,所以,使用時就要注意:有高價值、重用度高、數(shù)量少。這就是說,重寫一個類,就可以有一大批類可以用。

          二、Mock技術(shù)

          Mock是目前單元測試中最常用的。用來在對象層次上實現(xiàn)細類度替換十分方便。

          當我們在測試中,需要其它類/接口的一個方法時,我們可以通過繼承/實現(xiàn)其一個子類對象來替換實際對象。在Mock子類中將需要的方法直接返回需要的結(jié)果就行了。

              privateclass Mock_QueryCtrl extends QueryCtrl

              {

                 public List queryNEList()

                 {

                     List neList = new ArrayList();

                     //直接填充并返回你需要的數(shù)據(jù)...

                     return neList;

                 }

              }

          同樣,我們也可以通過測試待測類的子類來測試待測類。這對于被測方法使用了自身類的方法時很適用。

          三、依賴注入

          單元測試的一個關(guān)鍵就是替換。類層次上的替換,通過在類路徑中提前加載就可以實現(xiàn)。而在對象層次上,java的反射機制提供了很好的幫助。

          1.獲取/注入私有屬性

          2.執(zhí)行私有方法

          附:注入私有屬性的實現(xiàn):

              publicvoid setFieldObject(Object instance, String fieldName, Object value)

                     throws IllegalArgumentException, IllegalAccessException,

                     NoSuchFieldException {

                 Field field = null;

                 Class c = instance.getClass();

                 do {

                     try

                     {

                        field = c.getDeclaredField(fieldName);

                     } catch (SecurityException e)

                     {

                        e.printStackTrace();

                     } catch (NoSuchFieldException e)

                     {

                        c = c.getSuperclass();

                     }

                 }

                 while (c.getName() != "java.lang.Object" && field == null);

                 if (field != null)

                 {

                     field.setAccessible(true);

                     field.set(instance, value);

                 }

                 else

                 {

                     thrownew NoSuchFieldException(fieldName);

                 }

              }

          注:這是一個簡單實現(xiàn),實際中需要優(yōu)化。

          四、實例:

          下例演示了如何測試類NEListTableShowNETable()方法。其中注意的是,方法中調(diào)用了類QueryCtrlqueryNEList()方法。

          待測類:

          publicclass NEListTable

          {

              QueryCtrl ctrl = null;

             

              publicvoid ShowNETable()

              {

                 List neList = ctrl.queryNEList();

                

                 for(int i = 0;i<neList.size();i++)

                 {

                     //neList轉(zhuǎn)換為表格行

                 }

                

                 //顯示表格...

              }

          }

          publicclass QueryCtrl {

              public List queryNEList()

          {

                 returnnull;

              }

          }

          測試類:

          public class TestNEListTable extends TestCase

          {

              private NEListTable table = null;

              private TestHelper helper = null;

              public void testShowNETable()

              {

                 Mock_QueryCtrl ctrl = new Mock_QueryCtrl();

                 helper.setObjectField(table,"ctrl",ctrl);//Mock對象注入table

                 table.ShowNETable();

                 assertTrue(table.getRowCount()>0);

              }

             

              private class Mock_QueryCtrl extends QueryCtrl

              {

                 public List queryNEList()

                 {

                     List neList = new ArrayList();

                     //返回你需要的數(shù)據(jù)...

                     return neList;

                 }

              }

          }

          posted on 2008-07-10 22:14 wukaichun 閱讀(2024) 評論(4)  編輯  收藏 所屬分類: test

          FeedBack:
          # re: 單元測試(技能篇) 2008-07-21 21:34 切爾斯基
          Mock不是你說的這個樣子吧, 你這里說的mock其實是stub  回復(fù)  更多評論
            
          # re: 單元測試(技能篇) 2008-07-21 23:19 wukaichun
          @切爾斯基

          非常感謝.不知您的見解是什么?
          我的理解是:Stub的替換發(fā)生在類層面,而Mock則是對象層面. 前者粒度較大,更適合功能測試級;后者粒度相對較小,對于方法級的單元測試比較有效.
            回復(fù)  更多評論
            
          # re: 單元測試(技能篇) 2008-07-28 22:42 Growing
          沒錯,同意"切爾斯基"的說法,樓主的Mock其實就是Stub,Mock與Stub的區(qū)別我認為是在于:Mock不需要像Stub那樣增加類。而是通過目前使用較多的EasyMock和JMock等框架,通過動態(tài)代理等方式生成代理類,使用這個代理類代替被測試類的依賴對象。保證測試的獨立、隔離。  回復(fù)  更多評論
            
          # re: 單元測試(技能篇) 2008-11-19 14:54 網(wǎng)絡(luò)監(jiān)控軟件
          能不能介紹一些C++的單元測試框架。  回復(fù)  更多評論
            

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


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 大化| 浮梁县| 仁布县| 富阳市| 托里县| 莒南县| 陇川县| 台北县| 永清县| 三河市| 英山县| 监利县| 庆云县| 巴彦县| 虹口区| 化德县| 盐源县| 南平市| 安溪县| 甘德县| 舒兰市| 柳州市| 庆阳市| 临澧县| 陵川县| 义乌市| 岳阳县| 江安县| 南部县| 定日县| 渭源县| 辽阳市| 介休市| 宣武区| 寻甸| 区。| 当雄县| 邓州市| 普兰店市| 天气| 宾阳县|