<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    少年阿賓

    那些青春的歲月

      BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
      500 Posts :: 0 Stories :: 135 Comments :: 0 Trackbacks

    1 現有的單元測試框架
           單元測試是保證程序正確性的一種有效的測試手段,對于不同的開發語言,通常都能找到相應的單元框架。



           借助于這些單測框架的幫助,能夠使得我們編寫單元測試用例的過程變得便捷而優雅。框架幫我們提供了case的管理,執行,斷言集,運行參數,全局事件工作,所有的這些使得我們只需關注:于對于特定的輸入,被測對象的返回是否正常。
           那么,這些xUnit系列的單元測試框架是如何做到這些的了?分析這些框架,發現所有的單元測試框架都是基于以下的一種體系結構設計的。

     
           如上圖所示,單測框架中通常包括TestRunner, Test, TestResult, TestCase, TestSuite, TestFixture六個組件。
    TestRuner:負責驅動單元測試用例的執行,匯報測試執行的結果,從而簡化測試
    TestFixture:以測試套件的形式提供setUp()和tearDown()方法,保證兩個test case之間的執行是相互獨立,互不影響的。
    TestResult:這個組件用于收集每個test case的執行結果
    Test:作為TestSuite和TestCase的父類暴露run()方法為TestRunner調用
    TestCase:暴露給用戶的一個類,用戶通過繼承TestCase,編寫自己的測試用例邏輯
    TestSuite:提供suite功能管理testCase
           正因為相似的體系結構,所以大多數單元測試框架都提供了類似的功能和使用方法。那么在單測中引入單元測試框架會帶來什么好處,在現有單元測試框架下還會存在什么樣不能解決的問題呢?
    2 單元測試框架的優點與一些問題
           在單元測試中引入單測框架使得編寫單測用例時,不需要再關注于如何驅動case的執行,如何收集結果,如何管理case集,只需要關注于如何寫好單個測試用例即可;同時,在一些測試框架中通過提供豐富的斷言集,公用方法,以及運行參數使得編寫單個testcase的過程得到了最大的簡化。
           那這其中會存在什么樣的疑問了?
           我在單元測試框架中寫一個TestCase,與我單獨寫一個cpp文件在main()方法里寫測試代碼有什么本質卻別嗎?用了單元測試框架,并沒有解決我在對復雜系統做單測時遇到的問題。
           沒錯,對于單個case這兩者從本質上說是沒有區別的。單元測試框架本身并沒有告訴你如何去寫TestCase,在這一點上他是沒有提供任何幫助的。所以對于一些復雜的場景,只用單元測試框架是有點多少顯得無能為力的。
           使用單元測試框架往往適用于以下場景的測試:單個函數,一個class,或者幾個功能相關class的測試,對于純函數測試,接口級別的測試尤其適用,如房貸計算器公式的測試。
           但是,對于一些復雜場景:
    ? 被測對象依賴復雜,甚至無法簡單new出這個對象
    ? 對于一些failure場景的測試
    ? 被測對象中涉及多線程合作
    ? 被測對象通過消息與外界交互的場景
    ? …
           單純依賴單測框架是無法實現單元測試的,而從某種意義上來說,這些場景反而是測試中的重點。
           以分布式系統的測試為例,class 與 function級別的單元測試對整個系統的幫助不大,當然,這種單元測試對單個程序的質量有幫助;分布式系統測試的要點是測試進程間的交互:一個進程收到客戶請求,該如何處理,然后轉發給其他進程;收到響應之后,又修改并應答客戶;同時分布式系統測試中通常更關注一些異常路徑的測試,這些場景才是測試中的重點,也是難點所在。
           Mock方法的引入通常能幫助我們解決以上場景中遇到的難題。
    3 Mock的引入帶來了什么
           在維基百科上這樣描述Mock:In object-oriented programming, mock objects are simulated objects that mimic the behavior of real objects in controlled ways. A computer programmer typically creates a mock object to test the behavior of some other object, in much the same way that a car designer uses a crash test dummy to simulate the dynamic behavior. of a human in vehicle impacts.
           Mock通常是指,在測試一個對象A時,我們構造一些假的對象來模擬與A之間的交互,而這些Mock對象的行為是我們事先設定且符合預期。通過這些Mock對象來測試A在正常邏輯,異常邏輯或壓力情況下工作是否正常。
           引入Mock最大的優勢在于:Mock的行為固定,它確保當你訪問該Mock的某個方法時總是能夠獲得一個沒有任何邏輯的直接就返回的預期結果。
           Mock Object的使用通常會帶來以下一些好處:
    ? 隔絕其他模塊出錯引起本模塊的測試錯誤。
    ? 隔絕其他模塊的開發狀態,只要定義好接口,不用管他們開發有沒有完成。
    ? 一些速度較慢的操作,可以用Mock Object代替,快速返回。
           對于分布式系統的測試,使用Mock Object會有另外兩項很重要的收益:
    ? 通過Mock Object可以將一些分布式測試轉化為本地的測試
    ? 將Mock用于壓力測試,可以解決測試集群無法模擬線上集群大規模下的壓力
    4 Mock的應用場景
           在使用Mock的過程中,發現Mock是有一些通用性的,對于一些應用場景,是非常適合使用Mock的:
    ? 真實對象具有不可確定的行為(產生不可預測的結果,如股票的行情)
    ? 真實對象很難被創建(比如具體的web容器)
    ? 真實對象的某些行為很難觸發(比如網絡錯誤)
    ? 真實情況令程序的運行速度很慢
    ? 真實對象有用戶界面
    ? 測試需要詢問真實對象它是如何被調用的(比如測試可能需要驗證某個回調函數是否被調用了)
    ? 真實對象實際上并不存在(當需要和其他開發小組,或者新的硬件系統打交道的時候,這是一個普遍的問題)
           當然,也有一些不得不Mock的場景:
    一些比較難構造的Object:這類Object通常有很多依賴,在單元測試中構造出這樣類通常花費的成本太大。
    ? 執行操作的時間較長Object:有一些Object的操作費時,而被測對象依賴于這一個操作的執行結果,例如大文件寫操作,數據的更新等等,出于測試的需求,通常將這類操作進行Mock。
    ? 異常邏輯:一些異常的邏輯往往在正常測試中是很難觸發的,通過Mock可以人為的控制觸發異常邏輯。
            在一些壓力測試的場景下,也不得不使用Mock,例如在分布式系統測試中,通常需要測試一些單點(如namenode,jobtracker)在壓力場景下的工作是否正常。而通常測試集群在正常邏輯下無法提供足夠的壓力(主要原因是受限于機器數量),這時候就需要應用Mock去滿足。
            在這些場景下,我們應該如何去做Mock的工作了,一些現有的Mock工具可以幫助我們進行Mock工作。
    5 Mock工具的介紹
           手動的構造 Mock 對象通常帶來額外的編碼量,而且這些為創建 Mock 對象而編寫的代碼很有可能引入錯誤。目前,有許多開源項目對動態構建 Mock 對象提供了支持,這些項目能夠根據現有的接口或類動態生成,這樣不僅能避免額外的編碼工作,同時也降低了引入錯誤的可能。
    C++:   GoogleMock   http://code.google.com/p/googlemock/

    Java:   EasyMock   http://easymock.org/

           通常Mock工具通過簡單的方法對于給定的接口生成 Mock 對象的類庫。它提供對接口的模擬,能夠通過錄制、回放、檢查三步來完成大體的測試過程,可以驗證方法的調用種類、次數、順序,可以令 Mock 對象返回指定的值或拋出指定異常。通過這些Mock工具我們可以方便的構造 Mock 對象從而使單元測試順利進行,能夠應用于更加復雜的測試場景。
           以EasyMock為例,通過 EasyMock,我們可以為指定的接口動態的創建 Mock 對象,并利用 Mock 對象來模擬協同模塊,從而使單元測試順利進行。這個過程大致可以劃分為以下幾個步驟:
    使用 EasyMock 生成 Mock 對象
    ? 設定 Mock 對象的預期行為和輸出 
    ? 將 Mock 對象切換到 Replay 狀態
    ? 調用 Mock 對象方法進行單元測試
    ? 對 Mock 對象的行為進行驗證
    EasyMock的使用和原理:  http://www.ibm.com/developerworks/cn/opensource/os-cn-easymock/

           EasyMock 后臺處理的主要原理是利用 java.lang.reflect.Proxy 為指定的接口創建一個動態代理,這個動態代理,就是我們在編碼中用到的 Mock 對象。EasyMock 還為這個動態代理提供了一個 InvocationHandler 接口的實現,這個實現類的主要功能就是將動態代理的預期行為記錄在某個映射表中和在實際調用時從這個映射表中取出預期輸出。
           借助類似于EasyMock這樣工具,大大降低了編寫Mock對象的成本,通常來說Mock工具依賴于單元測試框架,為用戶編寫TestCase提供便利,但是本身依賴于單元測試框架去驅動,管理case,以及收集測試結果。例如EasyMock依賴于JUint,GoogleMock依賴于Gtest。
           那么有了單元測試框架和相應的Mock工具就萬事俱備了,還有什么樣的問題?正如單元測試框架沒有告訴你如何寫TestCase一樣,Mock工具也沒有告訴你如何去選擇Mock的點。
    6 如何選擇恰當的mock點
           對于Mock這里存在兩個誤區,1.是Mock的對象越多越好;2.Mock會引入巨大的工作量,通常得不償失。這都是源于不恰當的Mock點的選取。
           這里說的如何選擇恰當的mock點,是說對于一個被測對象,我們應當在外圍選擇恰當的mock對象,以及需要mock的接口。因為對于任意一個對象,任意一段代碼邏輯我們都是有辦法進行Mock的,而Mock點選擇直接決定了我們Mock的工作量以及測試效果。從另外一種意義上來說,不恰當Mock選擇反而會對我們的測試產生誤導,從而在后期的集成和系統測試中引入更多的問題。
           在mock點的選擇過程中,以下的一些點會是一些不錯的選擇
    ? 網絡交互:如果兩個被測模塊之間是通過網絡進行交互的,那么對于網絡交互進行Mock通常是比較合適的,如RPC
    ? 外部資源:比如文件系統、數據源,如果被測對象對此類外部資源依賴性非常強,而其行為的不可預測性很可能導致測試的隨機失敗,此類的外部資源也適合進行Mock。
    ? UI:因為UI很多時候都是用戶行為觸發事件,系統本身只是對這些觸發事件進行相應,對這類UI做Mock,往往能夠實現很好的收益,很多基于關鍵字驅動的框架都是基于UI進行Mock的
    ? 第三方API:當接口屬于使用者,通過Mock該接口來確定測試使用者與接口的交互。
           當然如何做Mock一定是與被系統的特性精密關聯的,一些強制性的約束和規范是不合適的。這里介紹幾個做的比較好的mock的例子。
           1. 殺毒軟件更新部署模塊的Mock
           這個例子源于一款殺毒產品的更新部署模塊的測試。對于一個殺毒軟件客戶端而言,需要通過更新檢查模塊與病毒庫Server進行交互,如果發現病毒庫有更新則觸發病毒庫部署模塊的最新病毒庫的數據請求和部署工作,要求部署完成后殺毒軟件客戶端能夠正常工作。
     

            對于這一場景的測試,當時受限于這樣一個條件,通常的病毒庫server通常最多一天只更新一次病毒庫,也就是說如果使用真實的病毒庫server,那么針對更新部署模塊的測試一天只能被觸發一次。這是測試中所不能容忍的,通過對病毒庫server進行mock可以解決這個問題。
           對于這個場景可以采取這樣一種Mock方式:用一個本地文件夾來模擬病毒庫server,選擇更新部署模塊與病毒庫server之間交互的兩個函數checkVersion(),reqData()函數進行Mock。
           checkVersion()工作原先的工作是檢查病毒庫Server的版本號,以決定是否觸發更新,將其行為Mock為檢查一個本地文件夾中病毒庫的版本號;reqData()原有的行為是從病毒庫Server拖取病毒庫文件,將其Mock為從本地文件夾中拖取病毒庫文件。通過這種方式我們用一個本地文件夾Mock病毒庫Server的行為,其帶來的產出是:我們可以隨意的觸發病毒庫更新操作以及各種異常。通過這種方式發現了一個在更新部署過程中,病毒庫Server的病毒庫版本發生改變造成出錯的嚴重bug,這個是在原有一天才觸發一次更新操作的情況下永遠也無法發現的。
           2. 分布式系統中對NameNode模塊的測試
     

           在測試NameNode模塊的過程中存在這樣一個問題,在正常邏輯無壓力條件下NameNode模塊都是工作正常的。但是線上集群在大壓力的情況下,是有可能觸發NameNode的問題的。但是原有的測試方法下,我們是無法對NameNode模擬大壓力的場景的(因為NameNode的壓力主要來源于DateNode數量,而我們測試集群是遠遠無法達到線上幾千臺機器的規模的),而NameNode單點的性能瓶頸問題恰恰是測試的重點,真實的DataNode是無法滿足測試需求的,我們必須對DataNode進行Mock。
     

           如何對DateNode進行Mock了,最直觀的想法是選擇NameNode與DataNode之間的交互接口進行Mock,也就是他們之間的RPC交互,但是由于NameNode與DataNode之間的交互信息種類很多,所以其實這并不是一種很好的選擇。
           換個角度來想,NameNode之上的壓力是源于對HDFS的讀寫操作造成的NameNode上元數據的維護,也就是說,對于NameNode而言,其實他并不關心數據到底寫到哪里去了,只關心數據是否讀寫成功。如果是這種場景Mock就可以變的簡單了,我們可以直接將DataNode上對塊的操作進行mock,比如,對一次寫請求,DataNode并不觸發真實的寫操作,而直接返回成功。通過這種方式,DataNode去除了執行功能,只保留了消息交互功能,間接的實現了我們的測試需求,且工作量比之第一種方案小很多。
           3. 開源社區提供的MRUnit測試框架
           在原有框架下,對于MapReduce程序的測試通常是無法在本地驗證的,更不用說對MapReduce程序進行單測了。而MRUnit通過一個簡單而優雅的Mock,卻實現了一個基于MapReduce程序的單測框架。

    基于MRUINT框架可以將單測寫成如下形式:

     

           在這個框架中定義了MapDriver,ReducerDriver,MapReduceDriver三個有點類似容器的driver,通過driver來驅動map,reduce或者整個mapreduce過程的執行。
           如上例,在driver中設定mapper為IdentityMapper,通過withInput方法設定輸入數據,通過withOutput方法設定預期結果,通過runTest方法來觸發執行并進行結果檢測
           他的實現原理是將outputCollector做Mock,outputCollectort中的emit方法實現的邏輯是將數據寫到文件系統中,Mock后是通過另外一個進程去收集數據并保存在內存中,從而實現最終結果的可檢驗(在自己的數據結構中比對結果)。
           實現的原理很簡單,這樣做mock就會精巧,只選擇最底層的一些簡單卻又依賴廣泛的點(依賴廣泛指模塊間的數據流通常都走這樣的點過)做mock,這樣通常效果很好且簡單
           當然這個例子中也有一些缺陷:1.因為在outputcollector層做mock的數據截取,使得無法過partition的分桶邏輯;2.這個框架是寫內存的,無法最終改成壓力性能測試工具。

    7 附錄
    1. EasyMock示例:
     

    posted on 2013-04-20 15:21 abin 閱讀(411) 評論(0)  編輯  收藏 所屬分類: easyMock
    主站蜘蛛池模板: 久久亚洲AV成人无码国产电影 | 免费H网站在线观看的| 亚洲卡一卡2卡三卡4卡无卡三 | 亚洲aⅴ无码专区在线观看春色 | 狠狠入ady亚洲精品| 污污的视频在线免费观看| 在线观看特色大片免费视频 | 久热免费在线视频| 国产人妖ts在线观看免费视频| 亚洲AV永久纯肉无码精品动漫| 人妖系列免费网站观看| 亚洲深深色噜噜狠狠爱网站| 亚洲成a∨人片在无码2023| 国产免费人视频在线观看免费 | 国产成人精品久久亚洲高清不卡| 日韩免费视频一区| 又硬又粗又长又爽免费看| 亚洲精品国精品久久99热一| 最近免费中文字幕mv在线电影| 国产亚洲精品线观看动态图| 久久青草国产免费观看| 亚洲人成7777影视在线观看| 18女人腿打开无遮掩免费| 五月天网站亚洲小说| a级毛片高清免费视频就| 亚洲人成色77777在线观看大| 久久er国产精品免费观看8| 亚洲激情中文字幕| 毛片免费视频观看| 国产成人一区二区三区免费视频| 七次郎成人免费线路视频| 久久久久亚洲精品美女| 女人被免费视频网站| www免费黄色网| 亚洲精品无码午夜福利中文字幕| 麻花传媒剧在线mv免费观看| 国产成人综合亚洲| 久久久亚洲欧洲日产国码aⅴ| 免费看美女被靠到爽的视频| 亚洲欧美日本韩国| 国产高清免费在线|