為功能測試構建通用mock server系統

發表于:2013-11-26來源:InfoQ作者:余昭輝點擊數: 標簽:mock server
為功能測試構建通用mock server系統.mock在單元測試中已經眾所周知?,F今我們有各種功能強大而又好用的mock框架,可以很方便的解除單元測試中各種依賴,這大大的降低了編寫單元測試的難度。而測試驅動開發(TDD)更進一步將mock作為一種設計手段,來輔助識別出元素之間交

  mock在單元測試中已經眾所周知?,F今我們有各種功能強大而又好用的mock框架,可以很方便的解除單元測試中各種依賴,這大大的降低了編寫單元測試的難度。而測試驅動開發(TDD)更進一步將mock作為一種設計手段,來輔助識別出元素之間交互的接口和職責。

  那么在功能測試(這里提到的功能測試指的是用戶級測試)這個層次,是否有必要使用mock呢?如果有必要又將如何構建呢?或者說是否有可能像單元測試中那樣構建一個通用的mock server系統呢?本文將根據我的實踐經歷,向大家介紹一個通用mock server系統的主要組成部分以及設計思路。

  Why

  現今的業務系統很少孤立存在,它們或多或少需要使用兄弟團隊或是其他公司提供的服務,這為我們的聯調和測試造成了麻煩。對于這種情況,我們常見的解決方案是搭建一個臨時的server,模擬那些服務,提供數據進行聯調和測試。這就是mock server的雛形。一般來講,搭建這種mock server系統比較簡單,不過它的功能也比較簡單,而且往往需要針對不同的接口重復開發。那有沒有可能像單元測試中使用的mock框架那樣構建一個通用的mock server系統呢?

  How

  觀察單元測試中的mock框架,我們會發現一般使用mock的流程是:

  init mock //創建mock對象

  config mock //設置mock期望

  setup mock //將mock對象設置給被測對象

  call //調用被測接口,被測接口里的代碼會調用mock對象

  verify //驗證

  拿mockito舉例:

  User expected = new User(“admin”, “12345”);

  //init

  UserDAO dao = mock(UserDAO.class);

  //config

  when(dao.findByName(“admin”)).thenReturn(expected);

  //setup

  UserService service = new UserService(dao);

  //call

  User actual = service.login(“admin”, “12345”);

  //verify or assert

  借鑒這種做法,我么就可以構建一個簡單的mock server系統,接下來的內容中,我們會在這個mock server的基礎上演化出比較完善的版本。

  相關廠商內容

  京東“宙斯杯”創新應用大賽開始了,100萬獎金等你拿哦!

  版本1(簡單的模擬值)

  假設我們需要mock的是HTTP接口。我們的mock server提供一個配置接口(對應著上面的config mock步驟),測試運行之前調用配置接口將需要mock的HTTP接口URL以及需要返回的值傳遞過去,mock server內部建立url 到返回值的關聯(這里就類似存在一個哈希表一樣)。Mock server還提供另外一個接口供被測系統調用。這是一個通用的接口,所有原先指向真實服務的地址全部被指向到該接口(可以通過修改配置或修改系統 hosts文件)。當該接口被調用時會尋找剛才建立的url 到返回值的關聯,并將mock的值返回。這樣一個非常簡單的mock server就構建出來了,對于一些簡單的聯調場景基本夠用。這個時候我們的mock server的原理圖如下面所示:

  版本2(提供調用參數的查詢)

  有了第一版的mock server,對一些只需要模擬值的場景是夠用了。但是,mock的作用僅限于此么?想想單元測試中的mock。在單元測試中mock框架除了能夠為被測系統構建輸入值外,還能捕獲到被測程序傳出的值,然后對這些值進行校驗。舉一個實際的例子:在我們的系統中經常需要向用戶發送短信,為了對發送的短信功能以及短信內容進行驗證,在沒有mock之前我們可能真的需要向真實手機發送短信,然后驗證。這不僅降低了測試效率,也增加了不少不可控因素。為此我給 mock server添加第三個接口:query接口。在被測系統調用mock接口時,mock會記錄下被測系統傳遞給mock接口的參數值,然后測試中可以調用 query接口查詢到記錄的值,在測試中可以對其斷言,而且這里記錄下的調用記錄還可以作為日志提供出來,提高系統的診斷能力。這樣我們的mock server的結構就變成:

  版本3(可以根據參數模擬)

  現在我們的mock server已經可以提供類似verify的功能了,但實際上它還不能算一個真正的mock。它也不能處理哪怕稍微復雜一點的情況。在實際中,我們經常需要針對不同的參數返回不同的值。舉個簡單的例子:我們mock一個支付接口,對于訂單號123我們期望支付成功,對于訂單234期望支付失敗。這就引入了我的mock server的兩個核心組件:extractor和matcher。Extractor組件主要用于從調用的參數上提取出參數值,然后轉換成 key/value的格式提供給后續的環節使用;因為請求的參數格式多種多樣(json,xml等),extractor 為此提供了統一的接口。

  Matcher組件的作用是在拿到extractor傳遞過來的key/value值后利用一些匹配器匹配到具體設置的期望上,所有匹配到的調用會返回對應的值。也就是說mock server內部不再是簡單的映射了。后面再介紹DSL部分的時候會介紹matcher使用的語法。這樣我們的mock server結構就演化成下圖:

  版本4(提供多種協議的支持)

  估計有人在抱怨,說了這么多這個mock server還只能mock HTTP接口啊,我們的系統中存在HTTP接口,RPC接口,SMTP接口等等。這是mock server中協議組件的職責。協議組件是mock server的入口,它提供多種協議的服務,并且解析出協議包數據,然后將數據交給extractor組件;除此之外,協議組件在收到上層的返回值后,會按照協議的格式返回給被測系統 。利用一些開源的類庫,我們可以很容易對一些通用協議提供支持,但對一些私有的二進制協議如果沒有現成的庫支持,要重新開發成本很大,不過我們可以從客戶端來解決這個問題,這在后續的文章中會有介紹。

原文轉自:http://www.infoq.com/cn/articles/auto-test-mock-server?utm_source=infoq&utm_medium=related_content_link&utm_campaign=relatedContent_articles_clk

国产97人人超碰caoprom_尤物国产在线一区手机播放_精品国产一区二区三_色天使久久综合给合久久97