https://mp.weixin.qq.com/s/vIxbtQtRRqgYCrDy7XTcrA
自動化接口差異測試-diffy
自動化接口差異測試-diffy
1、前言
大家好,今天小編向大家介紹一款自動化接口diff平台–diffy。diffy是twitter的開源項目,通過同時運行新/老代碼,對比運行結果,發現潛在bug。diffy的原理是作為代理,截取請求並發送至所有運行的服務實例,通過對比響應結果來發現每次迭代代碼中可能存在的問題。
2、diff測試
什么是diff測試呢?
diff就是對比,在這里是對代碼輸出結果的對比,具體來說,就是通過對比相同輸入,相同接口,不同代碼的測試,對比其結果的差異,從而發現潛在的bug。
為什么要做diff?
①、場景驗證:
比如某個接口返回的數據中的”name”字段獲取由user數據庫表改為mobile_user數據庫表,那么從接口角度來講,通過對比這個接口在新老版本代碼的返回結果,就可以知道其字段的基本正確性與差異性。
②、提升回歸效率:
就一般的接口測試來說,每次代碼迭代,除了對新接口的測試,還包括對老接口的回歸。如果通過手工回歸,那么隨着接口數量的增加,測試人員的工作量將同樣地線性增長,且效率將大幅降低。通過diff測試,可以發現相同接口下內部代碼邏輯變更對其輸出的影響,測試人員只需要對比diff接口的差異之處(或自動對比),從而大幅減少人工作業的工作量。
diff測試的一般方案
①、分別部署新、老代碼:其中老代碼為線上穩定版本,新代碼為新迭代的測試版本
②、構造測試數據:我們可以手工構造測試數據,也可以對線上的數據進行抽樣,用於diff測試
③、運行測試:使用測試數據分別在新、老代碼中運行,並捕獲測試結果
④、結果對比:對比新、老代碼,相同接口下的輸出,如果出現差異,則可以通過接口反向定位問題
diff測試的問題
在實際diff測試中,你會發現大部分的接口都會有一定差異,原因是這些響應中存在了噪音,噪音可能包括:
-
server響應中生成的時間戳
-
隨機生成的數字
-
系統服務間的有條件競爭
這些噪音難以完全清除,根據內部邏輯、接口定義的不同,噪音的類型也難以枚舉,那么怎么辦么?diffy能夠通過一定的方式,清除這類噪音,保證diff結果不被影響。
3、diffy平台
diffy的原理
根據diffy的github文檔,diffy可以作為代理,截取請求並發送至所有運行的服務實例,通過對比響應結果來發現每次迭代代碼中可能存在的問題。其中,diffy上運行了三類代碼實例:
①、線上穩定版本:一個運行線上穩定版本代碼的節點
②、線上穩定版本備份:同樣運行了線上的穩定版本,用於消除噪音
③、測試版本:待上線的測試版本,用於和線上環境代碼進行對比
整體架構如下:
如圖所示,diffy能夠比較primary(線上穩定版本)和secondary(線上穩定版本備份)的差異值,通過對這些差異值做減法來消除噪聲;通過比較candidate(測試版本)和primary(線上穩定版本)得到基本的diff結果;最后通過比對基本的diff結果與消除噪聲后的結果,得到最終的diff結果。
diffy部署
1、克隆代碼並構建
git clone https://github.com/twitter/diffy.git
cd diffy
./sbt assembly
2、在localhost:9990
部署primary(線上穩定版本)的代碼
3、在localhost:9991
部署secondary(線上穩定版本備份)的代碼
4、在localhost:9992
部署candidate(測試版本)的代碼
5、啟動diff服務:
java -jar diffy-server.jar \
-candidate=localhost:9992 \
-master.primary=localhost:9990 \
-master.secondary=localhost:9991 \
-service.protocol=http \
-serviceName=My-Service \
-proxy.port=:8880 \
-admin.port=:8881 \
-http.port=:8888 \
-rootUrl='localhost:8888'
6、對diffy發一些請求
curl localhost:8880/your/application/route?with=queryparams
7、在http://localhost:8888中檢查結果
如圖所示,我們可以看到每個請求在不同節點上的差異之處,如果點擊“Exclude Noise”,則可以消除噪聲,看到最終的diff結果。
4、結語
程序的測試可以證明程序有錯,但永遠無法證明程序無錯。
-戴克斯特拉(Dijkstra)
一段程序,對於測試人員,bug永遠是存在的,沒有發現只是測試手段的不足。希望各位同仁保持對bug的“恐懼”與對技術的好奇與探索。
https://mp.weixin.qq.com/s/RjajIPpCx92b7ddTHnrfbw
給回歸測試減負——Twitter Diffy實戰介紹
回歸測試是老司機們都頭疼的問題,Twitter Diffy則為這個問題提供了新視角。它基於穩定版本和它副本的輸出,對候選版本的輸出進行嚴格對比,以檢查候選版本是否正確,大大降低了回歸工作量。讓我們一起來了解一下吧!
前言
測試是軟件生命周期一個十分重要的環節,但項目在隨着版本的逐步迭代,功能日益增多,系統愈加復雜,當前迭代版本增加的功能相對上一版本已存在功能的比例越來越小,而每次我們都需要保證新增或修改的功能不影響上一版本已存在的功能。若要進行全方位回歸,這個測試的工作量將會很龐大的。而且可能幾百上千用例中才會發現一個甚至是0個問題,測試投入產出不成比例。而Twitter Diffy則為上述問題提供了較好的解決方案。它通過基於穩定版本和它的副本的輸出,對候選版本的輸出進行比較,以檢查候選版本是否正確。工作原理
Diffy充當一個代理角色,它能夠將來源請求分發到不同版本的系統中去,通過對各個版本系統的輸出進行對比,做出最終的結論。
Diffy 需要三個版本的系統,以實現它的噪聲過濾和對比功能,它們分別是:
-
候選版本:該版本是待測版本,相對於生產環境版本有着跟新的代碼;
-
穩定版本:該版本通常是已經上線版本,或者是已知功能正常的版本;
-
穩定版本副本:該版本是穩定版本的副本,和穩定版本運行相同的代碼,主要用於排除噪聲。
運行流程如下:
其中:
- 原始區別為候選版本和穩定版本之間輸出的區別,其中可能會包含上述的噪聲;
- 噪聲從穩定版本和其副本中獲得,如果兩個運行相同代碼的系統輸入相同輸出卻不同,則 Diffy 會認為這是不需要關心的噪聲。
基於上述兩個區別集合,Diffy 可以識別出候選版本和穩定版本真實的區別,這些區別很有可能就是一個缺陷。例如,圖中所示的例子,原始區別中包含了噪聲,通過穩定版本和穩定版本副本的對比,可以進一步過濾噪聲。項目實戰
簡單示例
安裝和使用Diffy的一般步驟如下:
-
安裝Diffy;
-
啟動候選服務、穩定服務和穩定服務副本;
-
運行Diffy;
-
發送請求&查看結果;
我們來看一個簡單的示例,來大致了解Diffy的工作過程和使用方式:
在成功安裝並運行Diffy后,啟動三個簡單的本地服務來對比:候選版本(返回“hello world”)、穩定版本(返回“hello!!!”)、穩定版本副本(返回“hello!!!”)。
通過Diffy代理服務發送待測試的請求到三個不同版本后,可以看到Diffy的差異結果如下:
從該示例的差異結果可以看到,共測試了一個請求,且該請求結果不一致,故失敗率為100%,查看具體詳情,發現不一致的地方為返回結果的具體值和長度不一致。因此,Diffy結果與對比的服務一致。
大麥實戰
大麥是一個商品數據運營的平台,我們在測試大麥及其他數據產品的過程中,常需要回歸舊版本的功能以保證不被當前版本需求所影響。由於完全回歸所有舊版本功能的工作量十分龐大,一般來說會先選擇主干功能及在需求分析過程覺得可能會被影響的功能作為回歸案例。但是這個過程會有以下幾個問題:
- 首先,非常耗時耗力,雖然只回歸主干功能和測試分析中覺得可能被影響的功能,但這個回歸量仍不容小覷;
- 其次,回歸覆蓋不全,由於並不是回歸所有的功能,仍然存在遺漏缺陷的可能性;
因此,在大麥測試中引入Diffy,將所有線上請求作為待測范圍,對比測試環境和線上環境,回歸覆蓋完全,且大大減少了回歸工作量。將Diffy運用到大麥中的主要步驟可參考如下流程圖,目前暫時將Diffy部署在本地:
具體步驟如下:1.部署Diffy:
此處先這里將候選版本設置為(test.xxx.com),穩定版本和穩定版本副本均設置為(xxx.com)。在實踐過程中發現Diffy可以直接代理到線上環境,而無法代理到測試環境。故實戰部署時,在Diffy代理和各版本地址間加了一層代理(暫用charles,后續會需要優化,詳見第3章節)。
2.發送請求:在使用Diffy時,需要通過Diffy代理服務發送待測請求,當然我們可以通過postman、curl等工具一個個發送,但筆者覺得太過繁瑣,可以優化。因此,實踐時,通過Charles工具記錄所有線上待測請求,然后利用Charles的Rewrite功能將xxx.com修改成Diffy的代理服務器地址,Cookie修改至最新,再重發。
3.查看Diffy結果
我們可以看到共有1167個請求,有118處差異,這些差異可分為以下幾類:
- 每次調用本身返回值就不同,如updatetime(可忽略);
- 測試環境和線上環境數據不一致(可忽略);
- 實時接口(可忽略);
- 軟件缺陷;
對於可忽略的差異,可點擊按鈕忽略。最后發現了兩處軟件bug,原因都在於測試和線上的配置不同。實戰總結
優化內容
在將Diffy引入到項目的過程中,為了更加方便快捷地使用該工具時,在Diffy現有基礎上優化了一些內容,上一小節已有簡單描述,現總結如下:
- Diffy無法代理到測試環境
在利用Diffy進行對比測試環境和線上環境的差異時,發現Diffy可以直接代理到線上環境,但卻無法代理到測試環境。經實踐,發現測試環境在使用http協議時會提示只能使用具體的ip+端口號形式,而改用https協議則又提示服務器錯誤,因此,考慮到Diffy可能內部的機制不適用於測試環境,故目前的方案是在Diffy代理和各版本地址間加了一層Charles代理。Diffy通過代理端口將請求發送至配置中定義的測試環境和線上環境地址,以此來比較不同版本之前的區別。由於現在Diffy無法直接將請求發送至測試環境,因此,解決思路是通過Charles代理轉發Diffy請求分別至測試環境和線上環境。此處之所以線上環境也用Charles代理轉發的原因是,測試環境和線上環境的協議不同,測試環境為http協議,線上環境為https協議。而Diffy配置時只能配置一種協議,因此,為了統一協議,Diffy配置時采用的是http協議,然后通過Charles轉發至線上(https協議)。
- 請求過多
在將Diffy應用到具體項目時,會發現每個項目一般都有眾多接口。若每次對比時,都一個個的發送請求,這個成本也較高。因此,可利用工具記錄線上的請求,然后重寫請求,再重發即可。本人采用的是Charles工具,其他可完成相同功能的工具也可以使用。步驟如下: A. 訪問線上環境,記錄請求並保存
B. 使用Charles Rewrite功能
設置對於來自於線上的請求,將其host(xxx.com)替換為Diffy代理服務器,且Cookie替換至最新,若有其他替換需求也可在此處自定義規則; C.重發請求后續優化Diffy中間代理方案優化
Diffy無法代理到測試環境域名的問題,目前是通過添加Charles代理的方式解決。但由於每個Charles只能配置一個代理端口,所以不同版本之間使用了不同機器。后續考慮是否能利用其它工具代替Charles,能在同一台機器上設置不同代理,簡化配置。另外,也可考慮修改源碼的方式,看是否能夠解決該問題。
歷史請求記錄優化
目前針對多個請求的Diffy是采用人工觸發請求、工具記錄並重發的方式解決,雖然在某種程度上已經較便捷,但是對於很復雜的項目,記錄所有請求的成本還是較高。后續考慮是否有其他方案,在無需記錄請求的前提下,可自動Diffy。
注意事項
此外,在使用Diffy時還需要注意:
可排除請求頭部差異
在使用Diffy時,可以看到有些差異是請求頭部導致的,並不是我們想要發現的內容上的差異,如cookie的差異,nginx版本的差別,不同服務器等等,可以在命令行中加入配置可忽略頭部差異:excludeHttpHeadersComparison=true穩定版本和候選版本數據不同問題
假設穩定版本和候選版本不是同一份數據,如大麥的自助分析,VIP App的有數頁面等。由於數據的不同導致產生了一些不是bug的干擾差異,需要人工排除,會產生一些人力成本。目前我們的有許多項目的測試環境和線上環境數據並不是完全一致的,因此,Diffy更適用於可以灰度發布的項目,可以做到兩個版本的接口數據完全一致。實時實時接口使用有成本由於實時接口時序和獲取數據鏈路可能有的些微差異,不同版本之間獲取到的實時數據可能會有些許差異,因此也會產生一些不是bug的干擾差異,需要人工排除。線上不能隨意操作的接口謹慎使用線上常存在一些不能隨意操作的接口,如VIP App中的易信播報,若真實發送該請求到線上,那所有用戶均會收到消息,給用戶造成不便。無法對重定向的接口DiffyDiffy無法對需要重定向請求進行轉發,因此用在重定向的接口上,Diffy的只是原接口的返回值。需要注意的是,上文所述的注意事項提示了一些不太適合Diffy的場景。除了個別幾個場景是Diffy完全不適用外,其余均指的是這些接口會產生一些需要一定成本才能排除的干擾差異。總而言之,這些場景下的接口使用Diffy會產生更多的成本,但應結合具體情況,權衡Diffy帶來的收益是否值得所需的成本。附錄
環境搭建
Diffy是Twitter使用scala語言開發的項目,並且在GitHub持續更新中,可以在Github上下載源碼編譯 twitter/Diffy ,使用Diffy步驟如下:
1.從Github上克隆Diffy源碼:
git clone https://github.com/twitter/Diffy.git
2.構建sbt:
cd Diffy
./sbt assembly
3.啟動候選服務、穩定服務、穩定服務副本
4.運行生成的jar包/或含有啟動Diffy的命令的可執行文件
其中,運行Diffy的參數含義可參考如下:
參數配置 |
含義 |
candidate='PC1:8888' |
待上線版本部署地址,即候選版本 |
master.primary='PC2:8888' |
已上線版本地址1,即穩定版本 |
master.secondary='PC3: 8888' |
已上線版本地址2,即穩定版本副本 |
service.protocol='http' |
http協議或https |
serviceName='Test Service' |
服務名稱 |
proxy.port=:9990 |
Diffy代理端口,所以請求都應從這個端口訪問 |
admin.port=:9991 |
通過http://PC0:8881/admin可查看請求狀況 |
http.port=:9999 |
查看界面,在這里可以比較差異 |
responseMode=primary |
代理服務器是否返回結果,默認(empty)無返回,可指定primary返回線上版本,secondary(同線上版本,用於噪音消除),candidate(待測試版本) |
allowHttpSideEffects=true |
Diffy考慮到安全性,POST,PUT,DELETE請求默認忽略,因此該參數為true則表示這三種類型請求仍能正常代理發送 |
excludeHttpHeadersComparison=false |
是否排除header的差異,不同服務器,cookie,nginx版本可能有所差異,設置為true可以忽略這 |
5.查看結果 可通過設置的Diffy代理端口先發一次請求(如PC0:9990)。 再根據前面運行Diffy命令設定的查看請求和查看頁面的端口號,可通過在瀏覽器輸入運行Diffy的ip+設定的端口號查看:
- 查看請求:http://PC0:9990/admin (admin.port)
- 查看差異:http://PC0:9999 (http.port)
除了利用Github的源碼進行搭建外,還有兩種方式也可以搭建Diffy。其一是直接利用jar包,但該方法或者使用docker的Diffy容器(https://hub.docker.com/r/diffy/diffy)進行搭建,在此不一一贅述。參考文獻在調研diffy的過程中筆者查閱了較多相關的文檔,其中與diffy相關的最主要的文獻如下,可供參考:https://www.infoq.cn/article/diffy-twitter-open-source-automation-testing-toolhttps://blog.csdn.net/liusf1993/article/details/85231239作者簡介余紛艷,網易嚴選測試工程師,負責數據線的質量保障工作。2018年東南大學通信碩士畢業后加入網易嚴選。