轉載自 https://tech.meituan.com/mock-server-in-action.html
背景
在美團服務端測試中,被測服務通常依賴於一系列的外部模塊,被測服務與外部模塊間通過REST API或是Thrift調用來進行通信。要對被測服務進行系統測試,一般做法是,部署好所有外部依賴模塊,由被測服務直接調用。然而有時被調用模塊尚未開發完成,或者調用返回不好構造,這將影響被測系統的測試進度。為此我們需要開發樁模塊,用來模擬被調用模塊的行為。最簡單的方式是,對於每個外部模塊依賴,都創建一套樁模塊。然而這樣的話,樁模塊服務將非常零散,不便於管理。Mock Server為解決這些問題而生,其提供配置request及相應response方式來實現通用樁服務。本文將專門針對REST API來進行介紹Mock Server的整體結構及應用案例。

名詞解釋
- Mock規則:定義REST API請求及相應模擬響應的一份描述。
- Mock環境:根據請求來源IP來區分的Mock規則分組。Mock Server可以定義多套Mock環境,各套環境間相互隔離。同一個IP只能對應一個Mock環境,不同的IP可以對應同一個Mock環境。
整體結構
Mock Server由web配置頁面Mock Admin及通用Mock Stub組成:Mock Admin提供了web UI配置頁面,可以增加/刪除請求來源IP到Mock環境的映射,可以對各套環境中的Mock規則進行CRUD操作;Mock Stub提供通用樁服務,對被測系統的各類REST API請求調用,返回預先定義好的模擬響應。為了提高樁服務的通吐,使得樁服務能在被測系統壓力測試中得到好的表現,我們開啟了5個樁服務,通過Nginx做負載均衡。Mock Server的整體結構如下圖所示。

數據存儲
- 將請求來源IP到Mock環境名的映射存儲到mock-env.conf中,mock-env.conf的每一行定義了一條映射,如:
192.168.3.68 閆帥的測試機環境
這條映射表明來源是192.168.3.68
的請求,使用Mock環境名為閆帥的測試機環境
的Mock規則。 - 將配置的Mock規則存放到<對應Mock環境名>.xml中,下面部分展示了Mock規則的存儲格式。
<configuration>
...
<mock id="716add4f-33f7-49ac-abf3-fc617712ffea" name="test001" author="yanshuai">
<request>
<uri>/api/test/.*</uri>
<method>GET|POST|PUT|DELETE</method>
<parameters>
<parameter name="name" value="test.*"/>
...
</parameters>
<headers>
<header name="nb_deviceid" value="1E[0-9a-zA-Z]+"/>
...
</headers>
</request>
<response delay="1000" real="false">
<statusCode>200</statusCode>
<format>application/json;charset=UTF-8</format>
<customHeaders>
...
</customHeaders>
<body>{"name":"閆帥"}</body>
</response>
</mock>
...
</configuration>
Mock Stub
當請求發送到Mock Stub時,Mock Stub會根據請求的來源IP找到對應的獨立環境名,然后根據獨立環境名獲取所有預定義的Mock規則,遍歷這些Mock規則,如果找到一條規則與接受到的請求匹配,那么返回預定義的模擬響應。如果找不到規則匹配,那么返回404錯誤。其中,規則匹配是根據請求中的uri/method/headers/parameters/body是否與Mock規則中定義的對應字段正則匹配來定的。

Mock Admin
- 打開Mock Admin配置頁面,如果尚未映射來源IP地址到環境,則點擊環境列表導航鏈接,進入環境列表頁面,點擊添加,輸入源IP及環境名,點擊確定按鈕,實現源IP到所設環境的映射。
- 點擊規則列表,規則列表頁面將默認羅列出default環境的所有Mock規則(如“語音登錄code獲取”規則)。重新選擇環境,可以羅列出所選環境中的Mock規則。每個Mock規則都處於詳細信息展開的狀態。點擊“全部折疊”按鈕,將把所有的規則詳細信息給隱藏;點擊“全部展開”按鈕,將把所有的規則詳細信息給展開。點擊“只顯示本人創建的規則”,將過濾得到mis賬戶用戶創建的規則。點擊“按創建時間排序”的開關按鈕,將實現Mock規則的升序/降序顯示。
- 點擊導航欄的“新建規則”選項,可以創建一個Mock規則,需要填寫規則名稱、請求及響應,並選中環境。對於請求,需要填寫URL及勾選Method,如果要求對於符合某種規則的請求才被Mock,則填寫對應的Headers/Parameters/Body Like,這些數據都是正則匹配的形式。對於響應,如果勾選了“返回真實響應”,則只需要關注延時(延時是指返回請求需要的sleep時間,單位是毫秒)。此時需要將請求的URL地址給寫完整了,需要包含host(IP)及port,不能只是path。如果不勾選“返回真實響應”,則將返回模擬響應。Status Code填寫返回碼,比如200,404;Format選擇返回數據的格式,比如json,html等;還可以返回自定義的Headers及響應的Body。點擊新建按鈕以后,如果創建成功,則提示成功創建,並跳轉到規則列表頁面。
- 對於一個創建好的Mock規則,可以點擊Action下拉菜單,進行操作。如果點擊“克隆”,則跳轉到“新建規則”頁面,並將克隆的Mock規則信息給填充進去;點擊“編輯”,則跳轉到更新頁面,更新頁面填充了要編輯的Mock規則信息;點擊“刪除”,則彈出確認刪除對話框,點擊確定按鈕,將刪除此規則;點擊取消按鈕,則取消刪除操作。如果此Mock規則處於詳細信息展開狀態,則可點擊折疊來隱藏詳細信息;如果處於詳細信息折疊狀態,則可點擊展開選項,將顯示詳細信息。上移選項,可以將Mock規則上移一位;下移選項,可以將Mock規則下移一位。
使用方式
- 修改被測服務的HTTP依賴,將依賴的IP和端口分別設置為mock.ep.sankuai.com和80,並重啟被測服務;
- 創建Mock規則;
- 調用被測服務的API,被測服務將調用Mock服務;
- 刪除Mock規則(可選)。
編程使用
創建/刪除Mock規則,除了可通過Mock Admin頁面配置外,Mock Server還提供了SDK方式,用戶可以通過編碼來使用Mock Server。
- 在Maven工程pom.xml中添加mock-client依賴
<dependency> <groupId>com.sankuai.meituan.ep.mockserver</groupId> <artifactId>mock-client</artifactId> <version>1.0.6</version> </dependency>
- 創建/刪除Mock規則
// 構造Mock規則 MockRule rule = new MockRule(); rule.setMockName("test-" + System.currentTimeMillis()); // Mock name必須設置 rule.setAuthor("yanshuai"); // author必須設置,設置為代碼編寫者的mis賬號前綴,比如lining03 MockRequest mockRequest = new MockRequest(); mockRequest.setUri("/api/test/" + System.currentTimeMillis()); // Mock請求的uri必須設置 /** * Mock請求的方法必須設置 * 如果只有GET請求,則寫成GET; * 如果有GET請求及PUT請求,則寫成GET|PUT; * 即用|分割請求方法,不能有空格。 */ mockRequest.setMethod("POST|GET"); // 必要的話,設置Mock請求的匹配header List<MockRequestHeader> mockRequestHeaders = new ArrayList<MockRequestHeader>(); mockRequestHeaders.add(new MockRequestHeader("device", "android2.3")); mockRequest.setHeaders(mockRequestHeaders); // 必要的話,設置Mock請求的匹配參數 List<MockRequestParameter> mockRequestParameters = new ArrayList<MockRequestParameter>(); mockRequestParameters.add(new MockRequestParameter("wd", "123.*")); mockRequestParameters.add(new MockRequestParameter("version", "v1")); mockRequest.setParameters(mockRequestParameters); rule.setMockRequest(mockRequest); MockResponse mockResponse = new MockResponse(); mockResponse.setDelay(1000L); // 設置Mock響應的延時 mockResponse.setStatusCode(200); // 設置Mock響應的狀態碼 /** * 設置Mock響應的格式 * 如果是json返回,則為application/json;charset=UTF-8; * 如果是文本返回,則為text/plain:charset=UTF-8; * 如果是xml返回,則為text/xml;charset=UTF-8; * 如果是html返回,則為text/html;charset=UTF-8。 */ mockResponse.setFormat("application/json;charset=UTF-8"); List<MockResponseHeader> mockResponseHeaders = new ArrayList<MockResponseHeader>(); // 設置Mock響應的header mockResponseHeaders.add(new MockResponseHeader("customHeaderName", "customHeaderValue")); mockResponse.setMockResponseHeaders(mockResponseHeaders); mockResponse.setBody("{\"code\":200}"); // 設置Mock響應的body rule.setMockResponse(mockResponse); // 創建Mock規則 final MockClient client = new MockClient(); String id = client.addRule("default", rule); // default為環境名,如果使用別的環境,則填寫別的環境名 // 調用被測服務的API,被測服務將調用Mock服務 // 省略調用代碼... // 刪除Mock規則 client.removeRule("default", id); // default為環境名,如果使用別的環境,則填寫別的環境名
典型案例
- 相同Mock環境,同一接口,不同參數,可以有不同的Mock結果
按照下圖,依次創建這兩條規則(順序相關),然后在default環境對應的機器上,訪問http://mock.ep.sankuai.com/user/v1/info?token=fake,返回{"code":401,"type":"sys_err_auth_fail","message":"invalid token"};訪問http://mock.ep.sankuai.com/user/v1/info?token=other,返回{"user": {"id": 29008301,"mobile": "15001245907","isBindedMobile": 1}}。
- 真實請求延時Mock
按照下圖創建規則,在閆帥的測試機環境
對應的機器上,訪問http://mock.ep.sankuai.com/api/v1/divisions,將延遲5s返回城市列表json串。
- 不同Mock環境,完全相同的接口參數,可以有不同的Mock結果
按照下圖創建規則,在閆帥的測試機環境
對應的機器上,訪問http://mock.ep.sankuai.com/cachier/paynotify返回值是failure;在支付php環境
對應的機器上,訪問http://mock.ep.sankuai.com/cachier/paynotify返回值是success。
- 頂
- 1
- 踩