本文整理自美團技術沙龍第77期《美團億級流量系統的質量風險防控和穩定性治理實踐》,主要介紹了對網路返回資料進行變異的客戶端健壯性測試實踐經驗。文章第一部分介紹客戶端健壯性測試的基本概念;第二部分分享了基於介面返回資料變異的App健壯性測試方案設計的思路;第三部分主要解讀了變異資料的構造和異常檢測方案設計;第四部分介紹了精簡變異資料的探索方案。
01 什麼是客戶端健壯性
在維基百科的定義中,健壯性(Robustness)是指一個計算機系統在執行過程中處理錯誤,以及演算法在遭遇輸入、運算等異常時繼續正常執行的能力。IEEE中將健壯性定義為系統或元件在存在無效輸入或壓力環境條件下可以正常執行的程度。早在1989年,Barton Miller首次提出了模糊測試的概念,透過向目標應用丟擲隨機字串的方式來測試UNIX應用程式的健壯性;而在1996年的Ballista專案中,研究人員探索根據API定義的資料型別,對作業系統或軟體介面進行自動化測試方法。兩個專案均以“無應用程式崩潰或掛起”作為測試驗證透過的標準。
在移動端App領域,健壯性可以理解為App執行時遭遇環境異常或者輸入異常時客戶端能夠繼續正常執行的能力。
其中,環境異常主要分為作業系統異常、外部環境異常、硬體環境異常三大類。比如記憶體不足、CPU負載過高、執行緒池滿載、記憶體分配失敗、網路連線失敗等。輸入異常主要分為系統輸入和使用者輸入。比如網路介面返回的資料異常、應用內快取、資料庫檔案讀寫異常,這類的異常屬於在系統輸入異常;在電話號碼輸入框場景,使用者輸入的空格、富文字則屬於使用者輸入異常。
對於這些風險,如果App沒有處理,理論上都可能會產生展示異常、互動異常、效能、安全等問題,導致使用者無法繼續使用或在使用過程中產生不好的體驗。比如使用者操作App下單過程中,API請求出現故障未返回狀態碼為200的響應,App由於沒有獲取到預期介面響應的資訊而發生崩潰,就會中斷使用者的使用流程。
02 基於介面資料變異的App健壯性測試方案設計
在實際的客戶端測試執行過程中,測試人員會考慮測試異常輸入的場景,但由於成本無法做到無窮盡的測試,同時還存在人工執行遺漏的風險。
從美團App平臺業務的歷史故障分析中,我們發現:網路請求返回的資料與實現預期不符引發的Crash或核心功能缺失問題導致的故障佔比最高,且影響面較廣。比如介面返回非預期資料時,客戶端處理資料型別轉換異常導致閃退,即使5分鐘內操作降級仍影響了百萬量級的使用者。因此美團平臺業務App的健壯性測試探索優先從發現網路請求返回資料導致的異常開始。
針對於發現請求介面返回客戶端非預期資料導致的Crash,或者核心模組缺失問題這個訴求,我們調研後發現方案的基本原理都是相似的,即以網路請求的原始響應為基礎,根據規則進行變異構造,使用代理工具改寫響應體返回給客戶端,在端上裝置做異常檢測。但是都存在一些問題不能滿足訴求,比如測試變異資料是根據預置或者自定義規則隨機生成組合,隨機性過大,不能有效攔截健壯性問題;但如果不做隨機,產生的用例組合量過大,測試不能在合理時間範圍內結束;另外在檢測能力方面,不具備發現業務異常或功能模組異常的能力。
因此,我們結合通用方案做了一些自定義改造,整體檢測方案包含靜態檢測和動態檢測兩部分。
- 靜態檢測,主要是指靜態程式碼掃描,將典型程式碼編寫規範問題轉化為自定義靜態程式碼掃描規則,管控增量程式碼,同時長期治理存量風險。比如自定義了PrimitiveParseDetector、ColorParseDetector,管控業務必須使用健壯性測試透過的工具類。
- 動態檢測是指結合觸發時機,構造並注入變異資料後,識別App執行時是否出現崩潰、掛起或業務功能模組異常。比如在整合事件/迴歸事件觸發自動化測試執行,構造觸發異常的資料進行動態測試,然後監測是否出現了異常。核心動作包含構造變異資料和完成檢測兩部分。比如將介面響應體中表示顏色含義的Key對應的Value值構造成非色值,然後檢測客戶端請求處理介面資料時是否出現崩潰或掛起。
下文重點介紹端到端的動態檢測方案。
03 變異資料的構造和異常檢測
對於美團App來說,首頁有多種形態,對於某種特定形態,除了控制請求資料外還需要控制實驗、策略等一系列因素,才能保證測試物件的唯一性。一個頁面中包含多個非同步請求,因此請求的構造也需要和頁面路徑關聯。這些都是採集變異所需的基礎資料時需要關注和控制的。
響應體由基本型別資料和複合型別資料組成,相同基本型別的資料可能具備不同的業務語義,需要根據語義的型別做變異規則的區分對待,才能保障業務場景覆蓋。
因此,如何保障變異資料構造的全面性和準確性,是我們面臨的首要挑戰。
要解決資料構造全面性問題,首先要解決頁面描述方案,這樣才能控制獲取基礎資料的唯一性。在解決方案中,我們構建了頁面描述的特徵規則,解決使用者視角的頁面標識問題。需要的資訊包含端資訊、頁面路由資訊、實驗策略賬號資訊、頁面標識模組合集等。透過頁面請求資料自動錄製的方式,自動更新迭代請求資料和頁面之間的繫結關係,使得基礎資料能夠隨需求迭代更新,從而透過變異規則構造生成的用例也能夠自動更新。
在用例變異生成構造上,對於響應體裡的Value設定了語義匹配規則,比如字串的語義可能代表顏色、頁面跳轉路由、動靜態資源連結(即圖片資源資料/影片檔案/GIF檔案),需要區分特徵分別按語義構造異常資料。比如在圖片的變異資料構造裡,除了需要構造非圖片連結情況外,還要考慮不同圖片格式、非圖片格式以及非合法的圖片剪裁格式拼接等場景。
我們對介面返回資料使用指令碼做了初步的語義分析,人工二次校正後建立了基本資料型別和語義的對映集合,結合基本資料型別邊界值和語義定義了初始的變異規則。然後對歷史的線上健壯性問題和線下測試發現的健壯性Bug的變異資料進行整理,作為增補的變異規則。
在自動化測試執行過程中,我們基於App可測性改造提供的能力,對測試場景進行了控制,同時基於佈局檢視的解析SDK、App異常上報SDK提供的能力,完成了對App異常的通用檢測。
04 變異資料的精簡方案
伴隨著變異規則的豐富,自動生成的資料量級是巨大的,資料的變異組合如果按照全覆蓋方式來生成組合數量就是指數級增長。比如對於1種有7種變異取值的變數,如果存在n個此型別變數,就會產生7^n種資料組合,並且在實際業務場景中很多組合情況是沒有意義的。
如何在保障用例構造全面性的情況下精簡變異構造的用例數,是我們面臨的第二個挑戰。解決方案包含2個策略:1)陣列元素結構一致時,刪減構造的用例數;2)結構不完全一致的陣列元素,引入編輯距離和並查集演算法判斷節點相似性,節點不相似,可以在一次資料生成裡做合併構造。
我們可以把請求響應的JSON理解成樹,第一個解決思路是判斷樹中節點、路徑的相似度,相似節點刪減構造。
如果路徑、節點相似,可以推測路徑即業務邏輯也是一致的,比如頁面上的一些列表元素,可能是資料結構物件完全一致陣列,如果對每個陣列物件中的每個元素進行全用例構造,生成的變異資料量極大,且對業務場景或程式碼邏輯的增量覆蓋有限,因此我們決定將構造邏輯最佳化,進行刪減構造。即假如陣列中元素的結構完全一致,那麼同含義的欄位可以為他們分配不同的變異構造值,然後刪減掉無效的構造情況。應用這種方法可以有效降低28%左右的用例構造數量。
如圖陣列的3個元素中均存在“resourceName”鍵值對,假如每個鍵值對有3種變異取值,按照全排列方式進行用例構造將會生成有9份變異資料,在刪減構造情況下,可以分別為它們構造一個特定的變異值,這樣變異生成用例數量可以從9減少為1。
在對業務介面返回資料的資料結構進行分析後,我們發現在層級越深的場景下,距離根節點越近的兩個節點,業務邏輯耦合和結構相似程度越低,它可以進行合併構造,相互邏輯之間不會產生影響,比如有兩個鍵值對,每個鍵值對的Value有3種變異取值,在合併構造情況下,可以從排列組合的6份資料減少到3份資料。
基於這個個思路,我們在實踐中引入了編輯距離和並查集演算法,以節點路徑為參照,對樹的每一層的每兩個節點計算編輯距離,生成一個n*n矩陣;同時以樹的高度減去節點位於的層數作為權重,修正編輯距離。基於這樣的計算,會產生多個編輯距離矩陣。
為了嘗試最大化合並構造用例效果,我們把編輯距離做了0,1矩陣轉化。其中,由於編輯距離為1的兩個節點可能存在業務邏輯耦合關係,必須放在同一個組裡分別構造,所以我們把編輯距離大於1的情況轉化成了0,最後得到了一個0,1的編輯距離矩陣。
在0,1矩陣情況下,我們使用了圖的連通性概念,如果A和B連通,B和C連通,那我們認為A和C連通,轉化到這裡的概念就是A和B相似,B和C相似,那麼A和C相似,它們應該被放在同一個組裡分開進行構造,那麼在同層元素構造時,我們會從每個分組裡取到一個節點,對這些規則進行變異組合構造。
基於以上兩個策略進行精簡後生成的變異資料量較精簡前降低了40%,同時程式碼覆蓋率沒有明顯變化,並且保持不變的健壯性問題發現能力。
美團App和優選App都接入了這個工具,在新需求階段可以人工觸發執行,還可以結合客戶端元件整合事件和迴歸事件做自動觸發。至今應用一年時間內,發現了幾十個問題。
05 總結及展望
在健壯性工具建設一期裡,我們實現了App頁面載入展示場景的健壯性問題檢測,支援崩潰、卡死和部分功能異常這三類異常檢測。另外,基於節點相似性最佳化變異資料生成策略能夠在保持效果不變的情況下有效控制測試時長,但是否有更優的合併演算法和推薦演算法,還需要更多的嘗試。
在後續工具的迭代還會繼續圍繞異常構造和異常檢測這兩個方向,支援更豐富的構造能力和檢測能力,以及更高效的構造效率。短期建設上,我們將會從業務視角出發豐富自動化變異資料生成建模,完善客戶端異常通用異常檢測能力,完成通用前後端互動的資料構造型別(比如:長連線訊息)的覆蓋;長期建設上,需要支援更豐富的資料和環境構造能力,透過智慧化用例生成,提升測試效率。
06 Q&A
Q1:節點相似的判斷依據是什麼?
A:從實際的response分析來說,兩個節點的路徑完全相似就是從根節點到最終的葉子節點上,它們的路徑命名完全相似,陣列裡兩個物件的結構完全一樣。
Q2:用例的生成能舉個例子嗎?
A:比如顏色色值的格式是#+6位字元,通常運營配置會出現的情況是忘記新增#,或色值複製中少了一位。在這種情況下,我們會構造一個色值,比如沒有返回#、色值位數不對、色值新增透明度,把這種場景作為構造情況,在配置裡新增上,最後用程式碼生成。
Q3:健壯性平時執行的頻率是什麼樣的?
A:第一個基於需求維度,需求維度需要人工觸發;第二個基於變更維度,當元件發生變更時,可以關聯到這段程式碼或者元件變更的頁面,然後觸發頁面對應的健壯性測試,執行頻率會受到元件變更頻率的影響;第三個在迴歸測試時,App的迴歸測試兩週一次,我們會把所有頁面以及它關聯的所有的用例都執行一次。
Q4:對於暴露給前端開發的介面,大部分是人為呼叫引數的變化,隨機性相對比較高,對於必填和非必填引數如何確認用例的範圍?
A:目前我們在實現的方案裡,沒有區分引數是必填引數還是非必填引數,所以對於整個資料介面返回裡的所有結果都會進行構造,產生的問題是對於非必返回的引數可能產生的問題,到底是否是需要解決的問題,這部分目前透過運營手段做確認。
Q5:首頁可能呼叫10個介面,然後針對每個欄位都進行異常驗證嗎?
A:對於首頁關聯的介面,我們在介面請求、錄製過程中和錄製完資料後,會對介面進行確認到底有哪些介面是我們需要驗證的,這是一次性的成本,錄製完成後,會對每個欄位都進行異常驗證,當然會有一些黑白名單的設定。
Q6:對色號這種情況有一種生成規則嘛,這個規則是怎麼制定?
A:剛剛我只是舉了一個色號的例子,其實對於圖片、請求的資原始檔、配置檔案、跳轉連結,每一個對應到的業務語義,我們都有對應的用例生成規則,我們會根據參考依據,比如第一個是本身我們在通用的基礎庫裡怎麼處理這些問題,這裡有一個基礎的規則;第二個是我們積累了線上問題情況實際可能會產生的錯誤或者變異情況,生成第一版基礎規則,在第一期工具裡找相關研發達成共識,這樣的話,資料變異是處於合理範圍。
Q7:執行的時候,如何知道頁面對應哪些規則提前配置?
A:執行時,在測試接入過程中有一個配置過程,它不是配置這個頁面和介面的關聯關係,而是配置我們要測試哪些頁面,自動觸發自動化錄製過程,就是到這個頁面時,會觸發哪些介面請求,生成這個頁面和這個介面請求的對應關係,給到對應的配置人做確認,保證哪些介面是真正可能想要構造的,哪些介面不需要構造,最後以這個為基準測試,基於錄製過程,比如業務迭代裡面產生了新介面,我們在錄製中能夠感知到它關聯的介面發生了變化,在發生變化時發訊息給對應的測試提交人/負責人,TA確認這條規則放到黑名單裡還是更新到需要構造的介面裡。
Q8:是否有做頁面顯示的一個校驗?怎麼做的?
A:目前我們在頁面裡的模組做了“是否展示”校驗,基於當前整合到美團的可測性SDK,這個SDK會獲取到當前頁面是否渲染裡是否展示了對應模組的資訊,透過請求把對應模組描述傳給SDK,透過返回來校驗是否展示。
07 參考資料
- [1] 健壯性:https://en.wikipedia.org/wiki/Robustness
- [2] IEEE健壯性:https://ieeexplore.ieee.org/document/7438745
- [3] Ballista:Carnegie Mellon大學的研究專案,透過黑盒自動化測試的方式,發現導致系統崩潰或異常終止的系統呼叫或介面呼叫。
- [4] 基於佈局檢視的解析SDK:美團App頁面檢視可測性改造實踐-XraySDK
| 在美團公眾號選單欄對話方塊回覆【2023年貨】、【2022年貨】、【2021年貨】、【2020年貨】、【2019年貨】、【2018年貨】、【2017年貨】等關鍵詞,可檢視美團技術團隊歷年技術文章合集。
| 本文系美團技術團隊出品,著作權歸屬美團。歡迎出於分享和交流等非商業目的轉載或使用本文內容,敬請註明“內容轉載自美團技術團隊”。本文未經許可,不得進行商業性轉載或者使用。任何商用行為,請傳送郵件至tech@meituan.com申請授權。