推薦一款Diffy:Twitter的開源自動化測試工具

  • 2019 年 11 月 11 日
  • 筆記

1. Diffy是什麼

Diffy是一個開源的自動化測試工具,是一種Diff測試技術。它能夠自動檢測基於Apache Thrift或者基於HTTP的服務。通過同時運行新/老程式碼,對比運行結果,發現潛在bug。使用Diffy,只需要進行簡單的配置,之後不需要再編寫測試程式碼。

 

2. Diffy主要為了解決什麼問題

一個項目,從第一個版本發布到形成一個相對完善的版本,再到後面的重大更新甚至重構,需要經過許多版本的迭代。

而隨著項目的迭代,產品功能不斷增加,項目會變得越來越複雜。在後期,每修改增加的功能相對上一版本已存在功能的比例卻是越來越小。但每一次或大或小的版本升級,我們都需要保證新增或修改的功能不影響上一版本已存在的功能。但要達到這一點卻是困難異常,哪怕只改了一行程式碼、哪怕這項更改由非常優秀的開發者完成,我們都很難保證這項功能對上一版本的功能無任何影響。

 

要保證每次上線的安全,我們需要開發和測試完成兩項工作。一是,開發者在增加或變動某項新功能後,補充相應的測試用例,但寫過單元測試的同學都知道,完成一個單元測試用例所花費的時間可能比完成相應功能花費的時間更多得多。

 

大多情況只能寫幾個核心的測試用例,而在人員不足,時間緊張的情況下,則更是難上加難了。在後期,因為功能在不斷增加,回歸測試的工作量越來越大,同時因為是回歸,可能幾百甚至上千用例中才會發現一個問題,甚至一個問題也沒有,測試投入工作的時間與最終的收益不成比例。

 

另外測試人員對相同內容的重複測試,會有一種疲憊感,這樣一來會給測試人員帶來消極情緒,當真的有問題(尤其是較複雜的數據問題)發生時,也可能會因為這種疲憊而將問題忽略(如果一個用例測了10遍都沒問題,第11遍測的時候心裡可能會默認這個地方是沒問題的了)。這時候有些測試人員可能會考慮做自動化測試,但是自動化測試前期投入的成本較高,另外對測試人員的要求較高。如果項目變動比較頻繁,部分自動化測試可能需要重新設計,會帶來較高的成本。

 

而Diffy為上述問題提供了較好的解決方案,不同於我們常用的其他測試工具或框架從程式碼或介面的返回結果的正確性去驗證,而是如其名:通過程式碼的差異去驗證測試

 

需要注意的是:既然是差異,那至少是兩者之間比較才有差異,對於第一行程式碼或新增的功能無法比較,自然也就無法驗證,這時diffy無法發揮作用。但在後續增加修改,項目不停迭代的周期中,diffy就可以發揮它的舞台了,有了上一版本以及測試人員在上一版本測試工作的基礎,我們就通過上一版本和當前版本比較差異了。

3. Diffy適用場景

①、場景驗證:

比如某個介面返回的數據中的”name”欄位獲取由user資料庫表改為mobile_user資料庫表,那麼從介面角度來講,通過對比這個介面在新老版本程式碼的返回結果,就可以知道其欄位的基本正確性與差異性。

 

②、提升回歸效率:

就一般的介面測試來說,每次程式碼迭代,除了對新介面的測試,還包括對老介面的回歸。如果通過手工回歸,那麼隨著介面數量的增加,測試人員的工作量將同樣地線性增長,且效率將大幅降低。通過diff測試,可以發現相同介面下內部程式碼邏輯變更對其輸出的影響,測試人員只需要對比diff介面的差異之處(或自動對比),從而大幅減少人工作業的工作量。

4. Diffy一般操作流程

①、分別部署新、老程式碼:其中老程式碼為線上穩定版本,新程式碼為新迭代的測試版本。

②、構造測試數據:我們可以手工構造測試數據,也可以對線上的數據進行抽樣,用於diff測試。

③、運行測試:使用測試數據分別在新、老程式碼中運行,並捕獲測試結果。

④、結果對比:對比新、老程式碼,相同介面下的輸出,如果出現差異,則可以通過介面反向定位問題。

 

5. Diffy工作原理

在測試過程中,Diffy充當一個代理,它能夠將來源請求分發到不同版本的系統中去,通過對各個版本系統的輸出進行對比,做出最終的結論。

Diffy需要三個版本的系統,以實現它的雜訊過濾和對比功能,它們分別是:

  1. 候選版本:該版本是待測版本,相對於生產環境版本有著跟新的程式碼。

  2. 穩定版本:該版本通常是已經上線版本,或者是已知功能正常的版本。

  3. 穩定版本副本:該版本是穩定版本的副本,和穩定版本運行相同的程式碼,主要用於排除雜訊。

 

整個運行流程為:

 

 

如圖所示,diffy能夠比較primary(線上穩定版本)和secondary(線上穩定版本備份)的差異值,通過對這些差異值做減法來消除雜訊;通過比較candidate(測試版本)和primary(線上穩定版本)得到基本的diff結果;最後通過比對基本的diff結果與消除雜訊後的結果,得到最終的diff結果。

 

其中:

  • 原始區別為候選版本和穩定版本之間輸出的區別,其中可能會包含上述的雜訊。

  • 雜訊從穩定版本和其副本中獲得,如果兩個運行相同程式碼的系統輸入相同輸出卻不同,則Diffy會認為這是開發人員不需要關心的雜訊。

 

基於上述兩個區別集合,Diffy可以識別出候選版本和穩定版本真實的區別,這些區別很有可能就是一個缺陷。

當然,對於一個概率性出現隨機值,僅僅一次請求的結論可能是不準確的。例如對於一個50%概率出現true或者false的布爾值,則有50%的概率會出現候選版本和穩定版本的不同,同時又會有50%的概率出現穩定版本和其副本出現不同(即將這個值認定為雜訊),最終會有25%的概率認為這是一個缺陷。因為此時穩定版本和其副本值相同,候選版本和穩定版本值不同。因此,Diffy還會聚合原始區別和雜訊,當發現二者出現的概率類似的時候,會認定之前識別出來的缺陷屬於誤報。

6. Diffy安裝、使用

1、克隆程式碼並構建

git clone https://github.com/twitter/diffy.git  cd diffy  ./sbt assembly  

 

下載diffy-server,也可以在github上下載源碼編譯 twitter/diffy , diffy是twitter使用scala語言開發的項目,在安裝了jdk的基礎上,還需要安裝scala和sbt(類似於maven), 另外有些jar包需要從twitter下載,可能需要vpn。

2、例如,在localhost:9990部署primary(線上穩定版本)的程式碼。

3、例如,在localhost:9991部署secondary(線上穩定版本備份)的程式碼。

4、例如,在localhost:9992部署candidate(測試版本)的程式碼。

5、在下載好jar包之後,可直接通過java命令啟動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'

 

各參數詳細說明:

candidate='localhost:9200'  (待上線版本部署地址)  master.primary='localhost:9000' (已上線版本地址1)  master.secondary='localhost:9100' (已上線版本地址2)  service.protocol='http'  (http協議或https)  serviceName='My Service'  (服務名稱,無影響)  proxy.port=:8880  (diffy代理埠,所以請求都應從這個埠訪問)  admin.port=:8881 ( 通過http://localhost:8881/admin可以查看請求狀況)  http.port=:8888 (查看介面,在這裡可以比較差異)  rootUrl='localhost:8888' (同上)  responseMode=primary (代理伺服器是否返回結果,默認(empty)無返回,可指定primary返回線上版本,secondary(同線上版本,用於噪音消除),candidate(待測試版本)  excludeHttpHeadersComparison=false (是否排除header的差異,不同伺服器,cookie,nginx版本可能有所差異,設置為true可以忽略這些差異)notifications.targetEmail=123@emal.com (對差異發送到指定郵箱)  

 

需要注意的是,為了防止測試對數據造成不必要的影響,diffy默認只支援讀,即Post及Delete影響數據的等請求不會轉發,如果需要支援這樣的請求,需要增加參數。

allowHttpSideEffects=true  

 

命令模板(根據實際情況修改參數值即可)

java -jar diffy-server.jar -candidate=localhost:8086 -master.primary=localhost:85 -master.secondary=localhost:85 -service.protocol=http erviceName=My-Service -proxy.port=:8880 -admin.port=:8881 -http.port=:8888 -rootUrl='localhost:8888' -allowHttpSideEffects=true

 

6、對diffy發一些請求
curl localhost:8880/your/application/route?with=queryparams

7、在http://localhost:8888中檢查結果,結果展示如下圖

 

 

如圖所示,我們可以看到每個請求在不同節點上的差異之處,如果點擊“Exclude Noise”,則可以消除雜訊,看到最終的diff結果。

 

 

 

7. 小結

上述對diffy作了一些基本的介紹和使用引導,利用diffy結合gor及nginx或filter等手段還可以擴展很多其它的測試實踐。關於gor的介紹和用法可查閱:推薦一款簡單易用線上引流測試工具:GoReplay,diffy更多高級用法,歡迎大家自行探索。