淺談WireMock結合Mock+Proxy應用於異常測試

來源:互聯網
上載者:User

標籤:

淺談WireMock結合Mock+Proxy應用於異常測試

 

為什麼需要WireMock

最近在做NCE自動化介面測試,按照儘可能覆蓋邏輯的原則,寫了200+用例,但實際去實現的時候,大概能做的就100不到,完成的大多是能通過傳入參數去控制系統的邏輯走向和結果的case,即傳入指定的參數,調用發送請求工具,對結果進行校正。那麼除此之外,哪些是難以實現的呢?
從被測系統本身來說,NCE是建立在底層服務之上的一套系統,他的主要職能還是資源分派和調度,比如調雲主機的介面拿兩台機器,又去申請幾塊硬碟掛上,然後還要在機器上部署k8s的組件,調k8s建立rc和pod等,考慮到調用以非同步為主,還要加上輪詢,所以大量的調用外部的介面,以及結果判斷的邏輯。而調用外部服務,想要獲得預期的結果,並不是那麼容易,需要額外瞭解什麼情況下才會出現異常,有些情況難以類比又不能跑去把公用的服務搞壞。這不僅僅是自動化容易遇到的問題,手工測試也同樣會遇到。
這種上層服務測試所遇到的問題一般是怎麼解決的呢。就之前的經驗來說,需要藉助mock來實現,比如之前在支付,後台依賴的是財付通的服務,很多異常需要由財付通後台返回,另外由於測試環境是對接的,財付通做異常測試或是環境出現問題的時候,支付的正常的測試活動就不能自理了,所以需要mock來降低對外部環境的依賴。僅有mock還是不夠,如果一個人mock了一個服務,那麼所有人都走到了被mock的服務上,如果被mock的返回是異常,那麼所有人的測試活動又沒有辦法進行,如果被mock返回的是成功,對別人又是一種誤導。所以最後採用的是一種mock+選擇的模式,一般以帳號+介面名為維度來控制請求訪問指定的目的地,

如果要對NCE系統做異常測試,mock是比較容易找的,由於協議都是http協議而不是什麼自封裝的協議,所以選擇比較多,其中WireMock是一種較好的選擇,之前有同學已經推薦過了WireMock——輕量級HTTP Mock伺服器),自己嘗試過一下,也夠簡單易用。分發方面,可以考慮python的HTTPServer做一個轉寄伺服器,收到請求後,解析請求串轉寄給想要的url,然後把請求返回回去
但還要加上規則匹配什麼的就覺得心好累,後來發現WireMock自己就支援即時設定這種更為簡單的方式,就轉為全都依賴WireMock

首先要做的——外部存取的統一管理

目前的服務訪問外部的url都是在設定檔中,如果每次都要改url配置指向mock,用mock測完再改回來無疑是一種低效的做法,結合WireMock的proxy功能希望能對所有可能的外部存取進行管理
使用WireMock proxy前的Container Service(舉例)

使用WireMock proxy後,我們所期望的

按如下步驟讓url都通過WireMock的proxy

1.下載並啟動WireMock-xx-standalone.jar

下載的WireMock的standalone,放到某台主機上

基本的啟動方式:

# java -jar wiremock-1.55-standalone.jar --verbose

java -jar wiremock-1.55-standalone.jar –help 有一些可以使用的命令,加–verbose開啟verbose資訊輸出到螢幕方便調試 ,當伺服器使用可以按如下命令掛在後台

# nuhup java -jar wiremock-1.55-standalone.jar &

 

歡迎頁面就是這個鳥樣:

然後將修改配置需要代理的連結切到WireMock,由看出WireMock預設連接埠8080,當然可以自己用–port指定。比如需要將kube的url從10.180.155.13:8080變為10.180.148.30:8080(WireMock連接埠)

啟動過WireMock後目錄下面有2個檔案夾:mapping和__file。mapping裡面是收發的規則配置,mapping裡面指定了返回的檔案名稱的話,就會從__file裡面把檔案給取出來,若規則匹配,則會返回對應的內容(預定的字串或檔案內容或網路錯誤),不匹配則返回404not found。
這裡要使用proxy模式,請求通過wiremock進行代理,在mapping裡面配置proxy規則,proxy的配置和mock配置類似,簡單配置如下

建立container-mapping.json檔案,加入一下配置
{    "request": {        "method": "GET",        "urlPattern": "/api/v1beta2/.*"    },    "response": {        "proxyBaseUrl" : "http://10.180.155.13:8080/"    }}

 

於是/api/v1beta2的http請求就從container->wiremock->kube,體驗上卻和直接container->kube一致


WireMock日誌

2015-05-30 12:09:48.36 Request received:GET /api/v1beta2/pods?labels=podlabel%3Dapitest-d5e3e7cf9bee471f8ff642d1258e1354-go00o HTTP/1.1User-Agent: curl/7.26.0Host: 10.180.148.30:8080Accept: */*2015-05-30 12:09:48.76 Proxying: GET http://10.180.155.13:8080//api/v1beta2/pods?labels=podlabel%3Dapitest-d5e3e7cf9bee471f8ff642d1258e1354-go00o

 

其他http連結也可以用這種方式配置好

採用WireMock做自動化異常測試

現在已經讓外部連結納入WireMock的控制了,如果想做網路異常或指定返回,可以添加另一個規則,將這個url對應的請求都返回指定值,但必然只有一個生效,比如

{    "request": {        "method": "GET",        "urlPattern": "/api/v1beta2/.*"    },    "response": {        "proxyBaseUrl" : "http://10.180.155.13:8080/"    }}{    "request": {        "method": "GET",        "urlPattern": "/api/v1beta2/.*"    },    "response": {        "status": 200,        "body": "mocked by hzmali!\n"        }}

 

實際情況下,誰在前面就優先使用那個規則,是否要每次做完異常測試需要再改回配置到正常方式呢,如果是手工測試還可以接受,如果是自動化測試,那麼就會很麻煩.幸運的是,WireMock 提供了通過__admin/mappings/new介面來遠程配置規則的功能。

嘗試在mapping下建立了一個test.json

{ "request": { "url": "/get/this", "method": "GET" }, "response": { "status": 200, "body": "on disk!\n" }}

 

重啟stansdalone,發現規則生效

curl "http://10.180.148.30:8080/get/this"on disk!

 

調用__admin/mappings/new配置/get/this返回NO

# curl -X POST --data ‘{ "request": { "url": "/get/this", "method": "GET" }, "response": { "status": 200, "body": "NO!\n" }}‘ http://10.180.148.30:8080/__admin/mappings/new# curl "http://10.180.148.30:8080/get/this"NO!

 

再配置/get/this返回YES

# curl -X POST --data ‘{ "request": { "url": "/get/this", "method": "GET" }, "response": { "status": 200, "body": "YES!\n" }}‘ http://10.180.148.30:8080/__admin/mappings/new# curl "http://10.180.148.30:8080/get/this"YES!
 

重啟standalone,之前配置的結果不存在,恢複為設定檔的結果:

#curl "http://10.180.148.30:8080/get/this"on disk!

 

各位看官大概可以猜想到,stanalone啟動時載入了本地的mapping配置到記憶體,/__admin/mappings/new這個介面將發送過去的規則置為最新規則,根據官方文檔的說法,最新的規則會生效:
By default, WireMock will use the most recently added matching stub to satisfy the request. However, in some cases it is useful to exert more control.(exert more control 指的是使用”priority”: 1,這樣的欄位來指定優先順序來破壞最近匹配的規則,目前沒有怎麼使用)

WireMock standalone能通過介面設定規則,以及最新生效這2個特性,對自動化用例絕對是一個喜大普奔的訊息,在類比外部資源返回特定訊息或異常時,可以採取這樣通用的方式:
1.正常case:外部存取都通過WireMock的proxy,映射關係都寫在本地配置,WireMock啟動就自動載入,不影響正常功能,上層無感知

2.需要mock的case:執行前將想要的返回以及匹配規則發送到/__admin/mappings/new介面使之生效,執行完成後重設規則使用proxy方式

簡單的tesng case寫法,通過設定規則控制返回是proxy的結果還是自己所期望的mock返回

/*WebUserParameterTestData.class的DataProvider*/    @DataProvider(name = "sample")    public static Object[][] sample(){        String jsonString="{\"request\": {\"method\": \"GET\",\"urlPattern\": \"/api/v1beta2/pods.*\"},\"response\": {\"status\": 200,\"body\": \"mocked by hzmali\"}}";        return new Object[][]{                {jsonString, "and"},        };    }/*case主要部分*/    @BeforeClass    @Parameters({ "env" })    public void init(String env) throws IOException, InterruptedException {        CommonData.init(env);        nce_conn = new NceHttpBiz(CommonData.WEBHOST);        mock_conn=new MockTool();        //列印當前結果        log.info("[befor test]response: "+nce_conn.getPods());        //設定規則放到test裡做    }    @AfterMethod    public void recoverMapping() throws IOException{        //恢複規則        String rule="{\"request\": {\"method\": \"GET\",\"urlPattern\": \"/api/v1beta2/pods.*\"},\"response\": { \"proxyBaseUrl\" : \"http://10.180.155.13:8080/\"}}";;        mock_conn.setMapping(rule);        //列印恢複後的結果        log.info("[after test]response: "+nce_conn.getPods());    }    @Test(dataProvider = "sample", dataProviderClass =WebUserParameterTestData.class)    public void sample(String rule,String expeted) throws IOException    {           System.out.println(rule);        //設定期望的返回        mock_conn.setMapping(rule);        //列印預期的返回        log.info("[testing]response: "+nce_conn.getPods());    }

 

列印的結果表示符合預期

[INFO ]17:32:34, [Class]NceHttpBiz, [Method]getPods, ==========call getPods=============[INFO ]17:32:34, [Class]MockCase, [Method]init, [befor test]response: {  "kind": "Status",  "creationTimestamp": null,  "apiVersion": "v1beta2",  "status": "Failure",  "message": "invalid selector: ‘podlabel%3Dapitest-d5e3e7cf9bee471f8ff642d1258e1354-go00o‘; can‘t understand ‘podlabel%3Dapitest-d5e3e7cf9bee471f8ff642d1258e1354-go00o‘",  "code": 500}[INFO ]17:32:34, [Class]MockTool, [Method]setMapping, ==========setMapping============={"request": {"method": "GET","urlPattern": "/api/v1beta2/pods.*"},"response": {"status": 200,"body": "mocked by hzmali"}}[INFO ]17:32:34, [Class]NceHttpBiz, [Method]getPods, ==========call getPods=============[INFO ]17:32:34, [Class]MockCase, [Method]sample, [testing]response: mocked by hzmali[INFO ]17:32:34, [Class]MockTool, [Method]setMapping, ==========setMapping=============[INFO ]17:32:34, [Class]NceHttpBiz, [Method]getPods, ==========call getThis=============[INFO ]17:32:34, [Class]MockCase, [Method]recoverMapping, [after test]response: {  "kind": "Status",  "creationTimestamp": null,  "apiVersion": "v1beta2",  "status": "Failure",  "message": "invalid selector: ‘podlabel%3Dapitest-d5e3e7cf9bee471f8ff642d1258e1354-go00o‘; can‘t understand ‘podlabel%3Dapitest-d5e3e7cf9bee471f8ff642d1258e1354-go00o‘",  "code": 500}

 

實際使用中,比如測試部署服務時,pod狀態不正確的情境,需要把查詢pod這個介面mock掉,kube其他介面都走proxy方式,實際用例會複雜一些

後記

WireMock的使用上也有一些不方便的地方:由於是proxy,所以如果有同名介面,需要使用額外的正則方式或是新的WireMock進程;目前期望的返回都是由用例來控制,可控性強,對於一些大粒度的異常情境類比較好,如泛失敗,網路錯誤等,但精確類比各種情境下正確的返回則需要花一點功夫,構造符合資料相關性的返回也是一個挑戰。目前只是初步使用,還有很多坑沒踩到,樂觀的來看這種方式能夠解決一些問題,而且代價不高,可以拿來先頂頂。

 

淺談WireMock結合Mock+Proxy應用於異常測試

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.