1 現有的單元測試框架
單元測試是保證程序正確性的一種有效的測試手段,對於不一樣的開發語言,一般都能找到相應的單元框架。node
藉助於這些單測框架的幫助,可以使得咱們編寫單元測試用例的過程變得便捷而優雅。框架幫咱們提供了case的管理,執行,斷言集,運行參數,全局事件工做,全部的這些使得咱們只需關注:於對於特定的輸入,被測對象的返回是否正常。
那麼,這些xUnit系列的單元測試框架是如何作到這些的了?分析這些框架,發現全部的單元測試框架都是基於如下的一種體系結構設計的。
web
如上圖所示,單測框架中一般包括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工做。
網絡