1. 程式人生 > >【介面測試】介面mock之基礎知識

【介面測試】介面mock之基礎知識

 Mock:In object-oriented programming, mockobjects are simulated objects that mimic the behavior of real objects incontrolled ways. A computer programmer typically creates a mock object to testthe behavior of some other object, in much the same way that a car designeruses a crash test dummy to simulate the dynamic behavior. of a human in vehicleimpacts.


、Mock操作方式的好處

  Mock通常是指,在測試一個物件A時,我們構造一些假的物件來模擬與A之間的互動,而這些Mock物件的行為是我們事先設定且符合預期。通過這些Mock物件來測試A在正常邏輯,異常邏輯或壓力情況下工作是否正常。

引入Mock最大的優勢在於:Mock的行為固定,它確保當你訪問該Mock的某個方法時總是能夠獲得一個沒有任何邏輯的直接就返回的預期結果。

Mock Object的使用通常會帶來以下一些好處:

  • 隔絕其他模組出錯引起本模組的測試錯誤。
  • 隔絕其他模組的開發狀態,只要定義好介面,不用管他們開發有沒有完成。
  • 一些速度較慢的操作,可以用Mock Object代替,快速返回。
  • 對於分散式系統的測試,使用Mock Object會有另外兩項很重要的收益。
  • 通過Mock Object可以將一些分散式測試轉化為本地的測試。
  • Mock用於壓力測試,可以解決測試叢集無法模擬線上叢集大規模下的壓力。

、Mock操作的應用場景

在使用Mock的過程中,發現Mock是有一些通用性的,對於一些應用場景,是非常適合使用Mock的:

  • 真實物件具有不可確定的行為(產生不可預測的結果,如股票的行情)
  • 真實物件很難被建立(比如具體的web容器)
  • 真實物件的某些行為很難觸發(比如網路錯誤)
  • 真實情況令程式的執行速度很慢
  • 真實物件有使用者介面
  • 測試需要詢問真實物件它是如何被呼叫的(比如測試可能需要驗證某個回撥函式是否被呼叫了
    )
  • 真實物件實際上並不存在(當需要和其他開發小組,或者新的硬體系統打交道的時候,這是一個普遍的問題)
  • 當然,也有一些不得不Mock的場景:
  • 一些比較難構造的Object:這類Object通常有很多依賴,在單元測試中構造出這樣類通常花費的成本太大。
  • 執行操作的時間較長Object:有一些Object的操作費時,而被測物件依賴於這一個操作的執行結果,例如大檔案寫操作,資料的更新等等,出於測試的需求,通常將這類操作進行Mock
  • 異常邏輯:一些異常的邏輯往往在正常測試中是很難觸發的,通過Mock可以人為的控制觸發異常邏輯。

  在一些壓力測試的場景下,也不得不使用Mock,例如在分散式系統測試中,通常需要測試一些單點(如namenode,jobtracker)在壓力場景下的工作是否正常。而通常測試叢集在正常邏輯下無法提供足夠的壓力(主要原因是受限於機器數量),這時候就需要應用Mock去滿足。

在這些場景下,我們應該如何去做Mock的工作了,一些現有的Mock工具可以幫助我們進行Mock工作。

、Mock操作相關工具介紹

  手動的構造 Mock 物件通常帶來額外的編碼量,而且這些為建立 Mock物件而編寫的程式碼很有可能引入錯誤。目前,有許多開源專案對動態構建 Mock物件提供了支援,這些專案能夠根據現有的介面或類動態生成,這樣不僅能避免額外的編碼工作,同時也降低了引入錯誤的可能。

通常Mock工具通過簡單的方法對於給定的介面生成 Mock物件的類庫。它提供對介面的模擬,能夠通過錄制、回放、檢查三步來完成大體的測試過程,可以驗證方法的呼叫種類、次數、順序,可以令 Mock物件返回指定的值或丟擲指定異常。通過這些Mock工具我們可以方便的構造 Mock 物件從而使單元測試順利進行,能夠應用於更加複雜的測試場景。

以EasyMock為例,通過 EasyMock,我們可以為指定的介面動態的建立 Mock 物件,並利用Mock 物件來模擬協同模組,從而使單元測試順利進行。這個過程大致可以劃分為以下幾個步驟:

  • 使用 EasyMock 生成 Mock 物件
  • 設定 Mock 物件的預期行為和輸出 
  • Mock 物件切換到 Replay 狀態
  • 呼叫 Mock 物件方法進行單元測試
  • Mock 物件的行為進行驗證

  EasyMock 後臺處理的主要原理是利用 java.lang.reflect.Proxy為指定的介面建立一個動態代理,這個動態代理,就是我們在編碼中用到的 Mock 物件。EasyMock 還為這個動態代理提供了一個InvocationHandler 介面的實現,這個實現類的主要功能就是將動態代理的預期行為記錄在某個對映表中和在實際呼叫時從這個對映表中取出預期輸出。

藉助類似於EasyMock這樣工具,大大降低了編寫Mock物件的成本,通常來說Mock工具依賴於單元測試框架,為使用者編寫TestCase提供便利,但是本身依賴於單元測試框架去驅動,管理case,以及收集測試結果。例如EasyMock依賴於JUint,GoogleMock依賴於Gtest。

那麼有了單元測試框架和相應的Mock工具就萬事俱備了,還有什麼樣的問題?正如單元測試框架沒有告訴你如何寫TestCase一樣,Mock工具也沒有告訴你如何去選擇Mock的點。

四、根據需求選擇恰當的mock點

  對於Mock這裡存在兩個誤區,1.是Mock的物件越多越好;2.Mock會引入巨大的工作量,通常得不償失。這都是源於不恰當的Mock點的選取。

這裡說的如何選擇恰當的mock點,是說對於一個被測物件,我們應當在外圍選擇恰當的mock物件,以及需要mock的介面。因為對於任意一個物件,任意一段程式碼邏輯我們都是有辦法進行Mock的,而Mock點選擇直接決定了我們Mock的工作量以及測試效果。從另外一種意義上來說,不恰當Mock選擇反而會對我們的測試產生誤導,從而在後期的整合和系統測試中引入更多的問題。

在mock點的選擇過程中,以下的一些點會是一些不錯的選擇

  • 網路互動:如果兩個被測模組之間是通過網路進行互動的,那麼對於網路互動進行Mock通常是比較合適的,如RPC
  • 外部資源:比如檔案系統、資料來源,如果被測物件對此類外部資源依賴性非常強,而其行為的不可預測性很可能導致測試的隨機失敗,此類的外部資源也適合進行Mock
  • UI:因為UI很多時候都是使用者行為觸發事件,系統本身只是對這些觸發事件進行相應,對這類UIMock,往往能夠實現很好的收益,很多基於關鍵字驅動的框架都是基於UI進行Mock
  • 第三方API:當介面屬於使用者,通過Mock該介面來確定測試使用者與介面的互動。
  • 當然如何做Mock一定是與被系統的特性精密關聯的,一些強制性的約束和規範是不合適的。這裡介紹幾個做的比較好的mock的例子。