天天看點

支付寶用例自生成技術實踐

講師簡介:

乾雨,螞蟻集團進階開發工程師。2018年加入螞蟻金服,現一直從事工程效能,智能化測試相關的工作。2018之前一直從事電商相關工作,參與過日均過億的網關開發工作。

熱愛技術,做過開源監控工具Onyxia,為公司産品打下穩定性的基礎,面對公司db中間件針對java語言的漏洞,重寫過對應的事務管理器,推動部門内java編寫的産品線能穩定上線。

本次分享分以下四個部分:

一、背景介紹

二、目前業内方案

三、支付寶的用例自生成實踐

四、總結和價值

戳我觀看視訊

一、背景介紹

支付寶用例自生成技術實踐

如圖所示,假如已經有一個作品線上上,當月提出一個需求,按照正常流程進行,開發完測試,驗收産品,産品如期上線。

但是在這個測試中大部分同學都比較側重于驗收新功能,對于之前已有的功能很少驗證或者不去驗證,下意識認為兩個功能點之間沒有關聯,不會出事情,但開發人員為了本次新功能開發需求,可能會改變業務代碼當中某些公共的方法,這些公共方法可能會服務已有的功能點,缺少測試驗證,上線後可能會導緻已有的功能異常,引發線上故障。

支付寶用例自生成技術實踐

如圖所示,即将有一個很複雜的功能要上線,要實作這個功能,代碼中有很多if...else或者switch...case的語句,并且排序計劃需要這個功能上線,那麼在時間有限的情況下,大家都會優先去保證核心鍊路的測試,其他鍊路的測試可能會簡單或者不去測試,甚至在測試過程中不會去考慮異常場景,比如說PPT中展示的例子,當type為空時,會有什麼影響,這些基本不會做驗證,上線之後未做詳細驗證的分支,很有可能有bug,引發線上故障。

支付寶用例自生成技術實踐

測試流程,在該流程中,查bug會占比較長的時間,無論自測,還是交給測試人員做,都會耗費長時間。回顧上述場景一、場景二,出現的問題都需要長時間測試才能避免。

支付寶用例自生成技術實踐

測試包括四種測試方法:單元測試、內建測試、系統測試、全鍊路測試。

測試用例:指覆寫更多分支的測試用例。比如說我有10個接口,每個接口有10個分支邏輯,那麼我需要用100個用例來覆寫所有的業務範圍,如果能有100個用例,上線之前全部跑一遍,無論結果如何,起碼業務分支都已經運作過,一些常見異常都能暴露出來,剩下要做的就是開發測試同學去檢視跑這100個用例的過程當中,是不是符合預期,有沒有業務邏輯的錯誤,如果我們能有這種大量的用例集合,那麼就會大大的減少測試成本,畢竟運作用例的時間是有限的,比查找bug的時間減少很多,這樣就會将之前業務上遇到的問題轉化為用例生成的問題。

一般來看,用例的來源主要有兩個方面:

①開發測試同學自己構造。這種方式依賴于編寫用例人員的多少,以及人員水準的高低,比如之前舉的例子,由于之前各種原因:項目周期短,人員少,隻會覆寫有限的人員邏輯,很難去覆寫所有的人員分支,甚至不會去管異常的用例;

②線上錄制。通過一些技術手段将線上發的技術參數錄制下來,當做測試用例,這種方式無法解決測新的問題。

比如我新寫了一個接口,或者将原來接口的參數做了改變,線上沒辦法錄制到最新接口的參數的請求,是以沒有辦法使用。

并且線上一般都是正常請求,很難去錄制到異常的參數,有些異常參數隻會在特定情景下複現,不能錄制到異常用例,并且這種方式錄制量很大,有可能錄制到100萬條用例,由于不知道這些用例對應哪些分支邏輯,是以會全部跑一遍,測試的時間很長,如果測試過程中異常較多,則還會做資料分析工作,比如100萬條用例,其中5萬條是失敗的,那麼就需要使用者去檢視失敗的用例是什麼原因導緻的,如果逐條去檢視,是不太可行的,中間就會需要聚類的方式,有一定排查和解決問題的成本。還有一些其他問題,比如說我們現在已經有一些用例集合,這時候還需要使用者去維護這些用例,當接口疊代更新的時候,需要把對應的用例更新,讓他跑用例的時候不至于随着時間的推移測試品質下降,這個也需要一定的成本。

針對上述提到的相關問題,我們要考慮如何将生成用例做到智能化和自動化,若用例覆寫度不夠,則自動生成需要的用例集合;若用例數目太多,則根據需要去縮減用例數量;若疊代有更新,那麼能動态感覺生成新的用例集合。

上述就是目前我們需要解決的問題。

智能化測試

支付寶用例自生成技術實踐

現如今智能化測試是一種大趨勢,現階段開發過程中,bug的查找、定位占用了大量時間、人力成本,很多人意識到這個問題,慢慢的向自動化發展,能自動查找問題,并且在自動化基礎上,加一些大資料和算法的支援,做到智能化的成産用例。

如今業内也有很多的方式方法去推進智能化的落地,比如學術界有一些論文,像《基于符号執行的方式》、《基于模糊測試的方式》、《基于模型的方式》等去生成用例,每種論文的方式或多或少都會有一些開源的項目去支撐這些論文的思想;工業界也有一些很有價值的工業産品,比如Randoop、Evosuite、AFl等,通過這些各式各樣的方法和工具,走出了多少人工才能查找定位走出bug死胡同。智能化的用例生成,将會減少很多查bug的時間,研發效率将會有很大的提升。

二、目前業内方案

Randoop、Evosuite

支付寶用例自生成技術實踐

Randoop和Evosuite都是比較好的開源工具,都能夠自動生成單元測試。

比如說有一個link list對象,現在想測試裡面用到的方法,通過運作各自支撐、支援的指令,可自動生成類似于PPT展示的單側用例,達到用例自生成的目的。生成的單側new了一個link list的對象,裡面設定了一個字元串,之後調用-isEmpty的方法去做測試。

觀察源代碼,發現有些資料是這樣實作的:通過随機值生成一些随機的資料放到裡面,或者說根據類型去設定。Evosuite裡面包含了GA的思想,它會根據覆寫率去進化生成的參數。

Randoop和Evosuite主要面向單側,而我們的業務方向可能面向接口測試,比如說我是一個接口測試平台,調用各個業務方的接口,那麼就不會去生成單側,因為沒辦法去了解業務的實作類是什麼,是以暫時不采用此方式。

AFL

支付寶用例自生成技術實踐

AFL是谷歌的一個工程師開發師,以代碼運作的路徑為指導,構造大量輸入參數,對軟體進行大量測試,進而發現問題的一種模糊測試方法。

與之前Randoop和Evosuite不同的是,它不會生成單側,比如像PPT中展示的那樣,使用者首先要準備參數的種子檔案,第一次可能不需要編譯,隻需要将種子檔案放在接口當中去做測試,測試過程當中對業務代碼進行插裝,計入本次代碼的執行路徑,如果跑到了新的路徑,那麼編譯的這個種子檔案将編譯後的種子檔案再輸入到應用程式當中,針對同一個接口繼續做測試。

AFL經過一些開源項目驗證,這種方法是可行的,但也有一些問題,這個相對來說,是比較适合C和C++的應用。如果要做AFL測試,必須要做一些種子檔案,種子檔案的品質和大小都有一定的限制。

接下來我們來看一些目前比較常用的用例生成方式。

第一種:組合測試

支付寶用例自生成技術實踐

組合測試:之前已經有一些用例集合,這些用例按照字段屬性單獨來看,id的範圍隻有三種,name的範圍隻有三種,age的範圍隻有兩種,那麼可以做兩兩組合來基于已有的參數編譯生成新的參數,如上圖所示。

第二種:交叉測試

支付寶用例自生成技術實踐

交叉測試與組合測試有很多相似地方,有如圖所示的一些集合,它針對某個參數有多個請求,那麼我們把這個參數拆開來看,我們将第一個用例的使用者對象和第二個用例的性别對象組合作交叉,再将第二個用例的使用者對象和第一個用例的性别對象再組合做交叉,這樣就會得到變異的一些參數,将這些參數再拿去進行測試,用來找到業務當中更多的問題。

支付寶用例的使用方式

支付寶用例自生成技術實踐

如圖:支付寶使用的方案有2種使用模式,生産模式和執行模式。

生産模式,顧名思義,就是遺傳算法,不斷變異參數,生成新的參數集合做測試。

為了要生成符合語義的變異參數,我們先做了一層代碼的解析,感覺到參數的組成結構,即就是說,參數是一個user對象,參數裡面有個id,還有name,要想知道它的結構和類型,進而生成參數的資料規約配置,解析出資料規約配置之後,能保證我們生成的參數都是符合語義的,之後到基因生成器子產品,這一部分是做資料的變異基礎,參數有多種多樣,有int、set,也有各種對象,有user,那麼我們如何做到公平的變異,就需要把各種各樣的參數全部轉化成同一個次元的資料,做一次歸一化處理,歸一化處理的結果我們就把它稱為參數的基因,本質上是一串數字,每一串基因序列都能夠唯一的對應一個參數值,當我們基因庫裡面沒有目前被測參數有效基因的時候,會自動生成一串随機的基因序列,這樣就能保證說需要種子檔案,我也能夠自動的去生成一個參數值。

如果我們基因庫裡面已經有一個有效基因,那麼就會對有效基因做變異,最終會生成一串基因序列。

這個基因系列是通過我們的參數解碼器,轉化為對應的用例參數原資料,這個源資料會服務一些測試平台,因為有些測試平台沒有被測接口請求測試的class,就是不知道它是否為一個user對象,是以我把這個源資料給到測試平台,測試平台能拿到我們的源資料,直接發起http或者rpc的請求,假如說我們的使用者可以提供class。

我們可以把源資料自動轉化為實際的用例,比如user對象,使用者拿着user對象去做測試,執行一次測試之後,會做一次适應度的計算,通過覆寫率為指導,指引下一個變異參數去覆寫更多的代碼行,而具體的參數變異,我們支援多種的變異算法,比如之前提到的交叉群組合,以及根據參數基因做編譯都做了支援。當然,如果使用者有有效的參數資料,也可以提供給我們,通過我們的參數編碼器轉成基因序列,儲存在基因庫裡面。

執行模式相對來說比較簡單,它會從之前基因庫裡面拿到沉澱的用例集合,重跑一次測試流程,用來驗證服務的穩定性。

自生成用例常見使用場景

我們現在支援從本地、IDE、測試平台、全鍊路測試、定時任務這幾種場景去跑用例流程的成産流程,主要是為了沉澱資料。

模糊測試很難說在非常短的時間内把大量的有效用例給生成出來,我們的用例自生成技術其實也相當于模糊測試的一種形态,有些應用可以配置個定時任務,比如每天淩晨2、3點左右,大家都在休息的時候,我們把服務拉起來跑一個用例生成功能,比如說我一個接口有10個分支邏輯,第一天隻生成出面向三個分支的基因,沒有達到要求,第二天繼續跑,之後在白天的時候來看一下結果即可,生成和測試都做到了自動化。

用例集也是會自動更新的,假如說今天生成了10個有效用例,然後代碼疊到了新的需求,代碼裡面删除了某些分支邏輯,那麼在下一次跑用例生成功能的時候,會自動的将這些删除的業務分支所對應的用例集給抛棄掉,保持用例的有效性。

沉澱下來的用例集之後,我們可以在持續內建某個階段去使用他們,比如使用者開發完功能,普适到目前的疊代,做了靜态檢測,做了代碼MR的合并,之後就可以用我們沉澱下來的用例重跑一遍,來驗證這次MR對之前的流程是否有影響,如果沒有影響,則可以合并至master,推到上限。

支付寶用例自生成技術實踐

變異測試過程當中,會生成大量的參數值。剛才提到的是遺傳算法篩選,保留對我們有用的參數,接下來來看其中的細節。

支付寶用例自生成技術實踐

這段代碼當中,有一個case語句,針對這個方法有三個分支流程,那麼生成一個參數之後我們會去儲存它走過的分支資訊。

比如我們生成了一個參數name=A,那麼它會走到a,這樣走過了一個分支,繼續變異這個參數,當下一次編譯的時候,走了相同的路徑,如果再次生成了A,那麼此時A沒有儲存的必要,因為代碼分支走的是一模一樣的路徑,保留一個即可,這樣就會簡化用例數量,從原來幾百個甚至上萬個用例最後過濾成幾個,運作執行模式的時候,将會大大的去減小測試的時間。

除此之外,我們在運作過程當中,還做了Trace的跟蹤,以及收集第一層業務的傳回值,比如a是個業務接口,我們會儲存a方法的傳回值i,我們隻會儲存業務接口的傳回值,不會儲存其他的傳回值。儲存業務接口的傳回值要做什麼?

支付寶用例自生成技術實踐

生産模式中,生成了參數A,參數A執行了各種業務接口,拿到它的傳回值user 、id、address,那麼當我們在持續內建階段,将沉澱的用例重新跑一下,還會生成A,那麼再收集到user’、id’、address’,正常來講,相同的參數,在業務流程中跑一下,它的傳回值應該都是一樣的,那麼我們可以做一個操作,比如說,我們會去判斷生産用例模式當中收集到的資料和執行模式當中收集到的資料是不是一樣的。

如果不一樣,業務同學就需要進去檢視一下,防止說某次疊代不小心改了一些公共的類,導緻服務異常。如果是非x等的接口,判斷就需要加一些規則,需要業務同學去檢視一下,加一些規則看是否符合業務預期。

接下來我們看一下實際當中我們是如何通過用例自生成來識别服務異常。

支付寶用例自生成技術實踐

如圖所示,針對test接口,生成的用例的參數,這個用例參數跑了多少行代碼,以及最後的結果都會展示給我們的使用者。

比如說像這個test,它的參數是一個複雜的對象,圖中顯示的參數資料就是我們生産出來的參數值,它覆寫了28行,中間有兩個業務方法的調用。

當使用者點選執行詳情的時候,就能看到中間業務調用方法的傳回值,然後點選覆寫率按鈕的時候,可以看到這條請求的Trace資訊。

這個Trace資訊不是指說當我做測試的時候整個應用的覆寫率資訊,而是指針對這個用例它跑過哪些行,我們會給收集起來,使用者通過這些資料就能比較清晰的感覺到:如果發生異常了就比較清晰的看到是什麼樣的異常,友善使用者去排查問題。

支付寶用例自生成技術實踐

支付寶用例自生成技術實踐

案例一:正常調用是沒有任何問題的,從業務邏輯上将,它請求參數的某些屬性是不能為空,通過用例自生成這項技術會生成正常的用例以及一些異常的用例,就是那些屬性為空的用例也會生成出來,将異常用例調用到服務端之後,能發現接口報異常了,跟蹤Trace的資訊以及檢視異常報錯能看到這種非空的校驗是放在了DB層,通過DB非空條件限制,滿足業務需求,這樣做的話,服務确實能穩定運作,能滿足業務需求,但這種做法其實是有隐患的,把業務參數直接通傳到了DB,請求量小的時候展現不出來,當請求量比較大,比如說搞一些營運活動,類似于雙十一活動的流量給DB帶來很大的壓力造成系統故障。

案例二:正常測試沒有問題,它的場景是我輸入一些查詢條件來查詢業務資料,但當有些業務屬性為空時,會将DB裡所有的資料查出來,然後針對這些所有資料的結果做便利,就是指對一個一個的資料去做業務處理。這種方式塞口沒有作業務兜底,如果一個資料為空時,DB裡所有的資料都查出來之後,導緻業務GC應用非常頻繁,它要做大量的業務處理,接口的耗時直接就增加了5倍,并且有大量的請求逾時。

案例三:相比較來說簡單,一般對外提供服務的接口,是不會對外抛出異常的,服務最外面會有一個trycatch,否則會把異常就去抛給了調用方,若調用方沒有處理,那麼就一層一層的往上抛,很有可能就會讓使用者感覺到,有個彈窗或者會顯示異常資訊。

通過用例自生成技術,我們也發現當滿足一些參數組合的情況下,有些對外提供服務的接口是抛出了未識别的異常。在這些項目實際運作當中,我們能看到測試覆寫率是有了顯著的增長,進而發現問題的能力也有所增強,提高了服務的穩定性,節省了一部分時間和人力的成本。

本文由社群志願者整理而成,設區内容志願者火熱招募中,有好禮相贈哦。歡迎加入!

戳我了解詳情加入!