qileilove

          blog已經轉移至github,大家請訪問 http://qaseven.github.io/

          自動化測試基礎設施(一)——為功能測試構建通用mock server系統

          mock在單元測試中已經眾所周知。現今我們有各種功能強大而又好用的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的基礎上演化出比較完善的版本。

            版本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組件;除此之外,協議組件在收到上層的返回值后,會 按照協議的格式返回給被測系統 。利用一些開源的類庫,我們可以很容易對一些通用協議提供支持,但對一些私有的二進制協議如果沒有現成的庫支持,要重新開發成本很大,不過我們可以從客戶 端來解決這個問題,這在后續的文章中會有介紹。

            版本5(模擬行為)

            基本上一個功能還算完善的mock server成型了。但這就夠了么?對于要模擬各種場景的測試還遠遠不夠。我們很多接口有回調的功能,我們通常還需要模擬接口超時的情況,而對于一些支付 相關的接口經常需要對參數進行加密解密,而且這些情況都需要是可配置的。有沒有發現,前面我們介紹的所有實際上都是mock值。也就是我們設置一些值,然 后調用的時候將值返回。但是很多時候我們不僅需要mock值,更要mock行為。這樣我們有了mock server中最核心的組件:命令執行引擎(好牛的名字,其實就那樣)。在設置mock的時候我們不再是設置一個值,而是設置一個預定義命令組合成的流水 線(即按照類似下面xml的配置一步一步執行,并且可以將上一步的執行結果傳遞給下一步):

          <delay>1000</delay>
          <callback url=http://localhost/callback.do>{“ret”:”true”}</callback>
          <return>{“ret”:”true”}</return>

            上面的流水線被命令執行引擎解析執行后就是按順序執行對應的DelayCommand, CallbackCommand以及ReturnCommand命令了,具體命令就不介紹了。采取這種方式給我們mock server帶來了很大的靈活性:只需要簡單的擴展一個子命令,就可以擴充mock server的行為。比如mock某網關接口時需要使用MD5加密,只需要擴展一個MD5Command(下面代碼中的$result表示前一步驟 <md 5 />加密后的結果):

          <md5 />
          <return>$result</return>

            DSL

            現在我們的mock不僅可以mock值了,對于各種行為的模擬也得心應手。但是要使用方便,還要提供便于使用的接口。Mock server提供兩類接口:針對自動化測試的DSL,以及針對手工測試使用的管理界面。這里主要介紹這種DSL(因為我們的測試用例是使用xml編寫,轉 換成編程語言也很容易):

          <mock service=”http:/test.json” matcher=”hasKey($param.orderNo)”>
              <delay>1000</delay>
              <md5 />
              <return>$result</result>
          </mock>

            service是對被mock的服務的描述,比如對于SMTP,我們可以這樣定義: service="smtp:9000"。這個表示在9000端口上監聽smtp協議。而matcher即前面介紹的matcher組件所使用的各種匹配 器,用于匹配被測系統調用mock server時傳遞的數據。比如上面的例子表示的就是如果被測系統調用http接口/ticket.jsp,并且參數里包含orderNo則延遲1秒鐘, 然后返回一個json值 。

            總結

            前面幾節介紹了一個比較完善的通用mock server從簡到繁演化的設計思路,希望可以為想要構建類似設施的讀者提供一個參照。

            這個mock系統包含兩個主要部分:mock admin和mock server。Mock admin是管理界面,主要提供監控(可以在界面上實時看到被測系統與mock server交互)以及手工測試時的配置界面。 Mock server即前面介紹的主體,其架構如上圖所示。Mock server包含幾個核心組件:協議、extractor、matcher、命令執行引擎、存儲(即mock server中使用的各種數據的存儲)。Mock server提供三類接口:配置、被mock接口(各種服務,通過協議組件提供)、查詢。

            原文:http://www.infoq.com/cn/articles/auto-test-mock-server

          posted on 2013-05-27 10:14 順其自然EVO 閱讀(361) 評論(0)  編輯  收藏 所屬分類: selenium and watir webdrivers 自動化測試學習

          <2013年5月>
          2829301234
          567891011
          12131415161718
          19202122232425
          2627282930311
          2345678

          導航

          統計

          常用鏈接

          留言簿(55)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 荔浦县| 苍南县| 镶黄旗| 龙陵县| 新化县| 磐安县| 七台河市| 北流市| 缙云县| 织金县| 定州市| 阳高县| 松阳县| 瑞金市| 舟山市| 永新县| 定州市| 德钦县| 乌恰县| 新邵县| 宁津县| 淮北市| 图木舒克市| 唐河县| 枞阳县| 静乐县| 察隅县| 沛县| 和林格尔县| 沙田区| 景德镇市| 彰化市| 宁国市| 大足县| 西乡县| 白河县| 石阡县| 雅江县| 甘孜| 西青区| 方正县|