張清睿,黃 松,孫樂樂
(陸軍工程大學 指揮控制工程學院,江蘇 南京 210007)
近年來Web應用變得越來越受歡迎,使用范圍變得越來越廣泛。因此,對Web系統的質量保證方法和工具的需求越來越高[1]。
軟件測試是軟件開發過程的重要組成部分,通過發現系統的故障從而提高系統的可靠性[2]。眾包測試是一種新興的軟件測試方式,可用性測試、性能測試和GUI測試等方面應用廣泛[3]。與傳統的軟件測試相比,眾包測試可以隨時隨地進行,從而極大地提高了測試效率[4]。
但是由于眾測工人水平參差不齊,測試用例書寫不規范的問題,眾測背景下Web測試用例自動生成技術應運而生。與基于軟件源代碼和基于需求文檔的測試用例生成方法相比,眾包測試更適用于基于測試工人操作記錄的測試用例生成方法。在測試用例自動生成的研究領域,一些大型商業軟件,如winrunner使用基于屏幕坐標的方法錄制回放測試腳本[5]。該方法不僅對測試人員的專業水平要求較高,而且當網頁修改后需要花費高成本重新錄制腳本。Paiva[6]提出了從用戶使用信息中自動生成測試用例的方法,通過OWA工具從系統日志中獲取用戶的頻繁操作路徑,然后通過自定義的規則集將其轉換為PHP語言編寫的測試腳本,但是該方法不適用于新研系統的測試。
因此,該文提出了一種基于眾測工人操作記錄自動生成測試用例的方法。該方法對Web頁面進行錄制,然后從龐大的錄制數據中提取出眾測工人的測試序列,并轉化為文本測試用例,這是一種無代碼化的測試用例生成方法。該方法不僅可以自動化地生成規范的測試用例,降低眾測的門檻,提高測試效率,還可以將眾測工人的操作進行回放,方便開發人員進行缺陷復現。
本節介紹了軟件測試中與操作記錄相關的研究。Paiva等提出了從用戶使用信息中自動生成測試用例的方法,通過OWA工具獲取用戶的頻繁操作路徑,然后通過自定義的規則集將其轉換為PHP語言編寫的測試腳本,但是該方法生成的腳本缺少測試數據,這些數據需要測試人員手動提供。Li等[5]提出了基于用戶行為建模的Web功能測試自動執行系統,可以記錄用戶的操作順序并自動生成XML格式的測試用例,通過組件類型和數據池的方式生成部分測試數據,但是該方法在實際應用中能夠生成的測試數據極少,有很大的局限性。龍測科技公司提出了Web自動化測試的方法,首先錄制測試流程,然后基于測試序列,測試人員可以通過搭積木的方式將對應的模塊拖拉拽到編輯屏幕上,再通過箭頭將序列連接,最終產生測試用例集合,這種無代碼的形式,極大地降低了測試的門檻。但是該方法生成的仍然是測試腳本,可以應用于回歸測試中,不適用于眾測領域。Selenium IDE是火狐瀏覽器的一個插件,用戶無需任何編程能力也可以生成測試腳本,只需記錄與瀏覽器的交互從而創建測試用例。Katalon Recorder支持錄制Web頁面操作,并能實現基本的數據驅動測試。Selenium IDE,Katalon Recorder等測試工具雖然已經降低了測試的門檻,但是還不能完全稱之為無代碼化的測試工具,因為這些工具將測試人員與Web應用程序的交互信息表示為一個三元組(命令,目標,值)形式的錄制腳本,對于不具備該領域知識的測試人員修改錄制腳本的難度仍然很大,并且這種腳本化的測試用例也不適用于眾測領域。Chang等[7]首次提出使用計算機視覺進行GUI測試的方法,測試用例可編寫為一個可視化測試腳本,該腳本使用組件圖像進行定位,降低了測試腳本編寫的難度。Kirinuki等[8]提出面向無腳本測試的Web元素識別方法,首先利用NLP技術從Web元素中提取相關信息生成字符串,然后判斷字符串與目標元素的相似性定位元素,進而生成DSL編寫(接近自然語言)的測試用例,但該方法目前只能處理簡單的操作,例如點擊、輸入和選擇。
上述研究適用于具有相關領域知識的專業測試人員,部分工具自動化生成水平較低,需要測試人員進行大量的手動調整。該文研發了一款使用簡單、自動化水平較高、適用于眾測工人的無代碼化測試用例自動生成工具,并且獲取的測試信息更完善,測試信息可以表示為一個四元組(組件名稱,組件類型,交互動作,交互數據)。
本節介紹了如何將眾測工人的操作記錄轉化為規范的測試用例。該方法可以劃分為四個階段:首先,錄制頁面信息和用戶的交互信息,其中頁面信息包含靜態頁面信息和動態頁面信息;其次,使用深度優先遍歷算法從錄制信息中獲取每個操作步驟的組件名稱、組件類型、交互動作和交互數據,并按照眾測工人的實際操作順序生成規范的測試序列;然后,通過n元組算法對測試序列中的錯誤信息進行修改;最后,通過自定義規則集將測試序列轉換為文本測試用例。測試用例生成流程如圖1所示。
rrweb[9](record and replay the web),一款針對Web頁面進行錄制、回放的開源庫,可以將頁面中的DOM以及用戶操作保存為可序列化的數據,以實現遠程回放。rrweb可以應用于很多應用場景,例如:
(1)記錄用戶使用產品的方式并加以分析,進一步優化產品。
(2)采集用戶遇到bug的操作路徑,予以復現。
(3)輕量級錄制,清晰度無損的產品演示。
作為一款Web頁面錄制工具,盡管rrweb的應用場景很廣泛,但是由于開源時間較短,目前網上與之相關的資料較少。該文的創新在于發現了錄制數據之間的聯系,并實現了從中提取測試用例的方法。

圖1 測試用例生成流程
頁面信息和眾測工人的交互信息由rrweb的錄制API收集,并以JSON字符串的形式存儲到數據庫中。當眾測工人在測試過程中發現缺陷時,可以將錄制的操作當作一種特殊形式的缺陷報告,有利于開發人員對缺陷進行回放復現,從而加快缺陷的修復速度。由于錄制的數據量龐大,在錄制時不錄制鼠標的移動事件,在錄制Form表單輸入數據時,不錄制輸入過程,只錄制最終的輸入結果。頁面的信息以DOM樹的形式進行存儲。眾測工人的交互信息中記錄了交互數據以及被操作組件的id。這些操作序列中具有大量的冗余、噪聲數據,需要進一步的處理。
在本小節中需要對錄制的原始數據進行處理,從而提取出眾測工人操作的組件類型、組件名稱、交互類型和交互數據等信息。
主要分為四個步驟:
(1)將錄制的JSON字符串轉換為自定義的對象類型,方便后續的查詢、封裝操作。
(2)獲取組件類型,如Input,Button,TextArea等。
(3)獲取組件名稱,如登錄模塊Button按鈕的組件名為登錄,Input輸入框的組件名為用戶名、密碼。
(4)獲取交互數據并根據組件類型進行分類從而生成交互動作,因為不同的組件類型具有不同的操作。
2.2.1 數據類型轉換
Fastejson是一個Java庫,可以將Java對象轉換為JSON格式,同樣也可以將JSON字符串轉換為Java對象。該文通過自定義類,使其與錄制的數據結構相符,并且類中的屬性覆蓋了錄制數據中絕大多數的變量。然后將錄制的JSON字符串轉換為自定義的DataAnaly對象類型。自定義類圖如圖2所示。

圖2 自定義類圖
2.2.2 獲取組件類型
因為交互信息中的id與頁面信息DOM樹中的id是匹配的,該文采用深度優先遍歷算法進行id匹配,從而獲取組件類型。深度優先遍歷算法會對每一條分支路徑深入到不可能再深入為止[10]。由于交互信息存在冗余,會出現多個相同的id,因此在保證原始操作順序的前提下需要對交互信息中的id進行去重操作避免重復查詢。
獲取組件類型方法如算法1所示。針對去重后的每個操作id,遍歷body下的節點,并將訪問過的節點進行標記,如果節點被標記則不再訪問該節點(見算法1中的第6~9行),如果節點中有子節點,則調用deepFindTagName( )函數繼續搜索其子節點(見算法1中的第10行)。遍歷子節點,如果id匹配成功則將獲取的組件類型封裝到Operate對象中,并將Operate對象添加至tagNames集合中(見算法1第16~21行),Operate具有幾個重要屬性,分別是tagName記錄組件類型,label記錄組件名稱,data記錄交互數據,action記錄交互類型。如果id沒有匹配到并且該子節點仍然存在子節點則遞歸調用deepFindTagName( )函數(見算法1中第23行)。動態頁面信息的獲取同樣采用深度優先遍歷算法查看adds節點下的node節點。
算法1:獲取靜態數據的組件類型算法。
Input:操作id的集合
Output:operate對象的集合
1. function findTagName(ids)
2. for i=0; i 3. Integer id= ids.get(i) 4. isfind= false 5. List 6. for j=0; j 7. if bodyNodes.get(j).getChildNodes() == null continue 8. if bodyNodes.get(j).isVisited() continue 9. bodyNodes.get(j).setVisited(true) 10. deepFindTagName(bodyNodes.get(j).getChildNodes(),id) 11. if isfind break 12.function deepFindTagName(childNodes, id) 13. for i=0; i 14. if childNodes.get(i).isVisited() continue 15. childNodes.get(i).setVisited(true) 16. if id == childNodes.get(i).getId() 17. String tagName= childNodes.get(i).getTagName() 18. isfind= true 19. Operate operate= new Operate() 20. operate.setTagName(tagName) 21. tagNames.add(operate) 22. break 23. deepFindTagName(childNodes.get(i).getChildNodes(),id) 2.2.3 獲取組件名稱 組件名稱的獲取分為兩種情況,一種是前端在編碼時通過標簽顯示組件名稱,這種情況下采用就近匹配的原則,通過深度優先算法獲取組件名稱;另一種是前端在編碼時不使用標簽,而是在組件內部顯示提示信息,這種情況可以直接獲取提示信息作為組件名稱。 第一種情況,組件名稱無法直接通過操作組件的id進行匹配,因為組件名稱與被操作的組件通常存在以下兩種關系,即左右相鄰關系和包含關系。因此需要對組件進行分類,然后針對不同類型的組件分別進行相應的操作。 (1)IF組件類型為Input,TextArea等THEN 采用深度優先遍歷算法自底向上遍歷其相鄰節點。 (2)IF組件類型為Button等 THEN遍歷其子節點。 針對第二種無標簽的情況,可以直接根據操作id采用深度優先遍歷算法獲取placeholder的屬性值(輸入框中的默認值)作為組件名稱。 2.2.4 測試序列生成 在獲取組件類型和組件名稱后,還需要獲取交互類型和交互數據。交互數據可以直接從測試工人的操作信息中進行獲取。為了獲取眾測工人的交互類型,需要對組件類型進行分類,因為不同的組件具有不同的操作,為此定義了一組規則集: (1)IF組件類型為Input‖TextArea THEN設置交互類型為輸入并獲取交互數據。 (2)IF組件類型為Radio‖CheckBox‖Select‖Date THEN設置交互類型為選擇并獲取交互數據。 (3)IF組件類型為Upload THEN設置交互類型為上傳并獲取交互數據。 (4)IF組件類型為Input Number THEN設置交互類型為點擊并獲取交互數據。 (5)IF組件類型為Button‖Switch THEN設置交互類型為點擊。 組件名稱、組件類型、交互類型和交互數據全部獲取后,按照眾測工人的操作順序有序地存放到集合中。雖然生成了規范的測試序列,但是測試序列中仍然存在噪聲數據,如點擊開始錄制和保存錄制按鈕的事件,以及一些并非測試工人操作生成的數據。為此,定義了一組規則集用于去除噪聲數據: (1)IF組件名稱為開始錄制‖保存錄制 THEN 去除該數據。 (2)IF組件名稱為空 THEN 去除該數據。 (3)IF 交互動作為空 THEN 去除該數據。 (4)IF 交互數據為空 &&組件類型不為Button THEN 去除該數據。 測試序列效果圖如圖3所示。 圖3 測試序列效果圖 上一節針對左右相鄰關系的組件和組件名稱,在匹配上采用了就近匹配的原則,但是該方法在Radio,CheckBox組件上存在匹配錯誤的情況,以單選框(性別 ○男 ○女)為例,當選擇男時,就近匹配原則不存在問題,獲取的測試信息為(組件名稱:性別,交互數據:男);當選擇女時,按照就近匹配原則生成的測試信息為(組件名稱:男,交互數據:女),很明顯獲取的組件名稱是錯誤的。除此之外,其他組件名稱匹配錯誤同樣可以通過n元組生成方法進行自動修改,例如輸入框可以生成(組件名稱,交互數據)二元組。 基于DOM的方法無法解決上述問題,新一代基于機器視覺的方法為Web應用復雜組件的測試提供了一種有效途徑[11]。該文利用YOLOv5算法構建了Web應用頁面組件識別模型,識別頁面組件類型并標注其位置;利用百度通用OCR接口識別頁面文字信息。OCR技術可以實時高效地定位并識別圖片中的所有文字信息,進而得到文字框位置與文字內容[12];最后通過n元組生成算法生成組件名稱與組件選項的對應關系或者是組件名稱與交互數據的二元組對應關系,并通過測試序列中的交互數據與n元組進行匹配,進而獲取正確的組件名稱,從而達到已生成測試序列中的錯誤測試信息自動修改的目的。n元組生成流程如圖4所示。 圖4 n元組生成流程 2.3.1 組件識別 本小節利用YOLOv5算法訓練了Web組件識別模型,從而識別組件的類型和位置。YOLOv5是Glenn Jocher在2020年提出的一種單階段目標檢測算法,采用了馬賽克數據增強方法,通過對輸入圖像進行隨機變換和拼接,在小目標檢測中表現更好[13]。由于Web系統主要是針對Form表單進行操作,該文選擇了Form表單中頻繁使用的12種組件進行識別,分別是Button(按鈕)、Radio(單選框)、CheckBox(復選框)、Input(輸入框)、InputNumber(計數器)、Select(選擇框)、Switch(開關)、Date(日期)、Upload(上傳)、Textarea(富文本框)、Rate(評分)、Slider(滑塊)。 數據集來源于Gitee中的各種商用以及開源Web系統,其中前端框架涉及ElementUI,Bootstrap,LayUI,EasyUI和Ant Design Vue,共搜集1 500張圖片,標注了12種頻繁操作的組件類型,按照7∶2∶1的比例隨機抽取訓練集、驗證集和測試集。通過對精度與識別速度的衡量選擇yolov5m.pt為預訓練權重,訓練時輸入圖像大小為640×640,初始學習率為0.001,最大迭代次數為400,batch-size設置為8。通過訓練后得到的模型在測試集上的組件識別的準確率如表1所示。 表1 測試集中組件識別的準確率 訓練完成以后,將該模型應用于Web頁面組件類型及位置識別。為了提高預測的準確率,將置信度設置為0.7,只有置信度大于0.7的組件才會在頁面上進行標注。 2.3.2n元組生成 OCR技術是利用光學技術和計算機技術通過檢測字符每個像素的暗、亮模式確定其形狀,然后用字符識別方法將形狀翻譯成計算機文字的過程[14]。在經過YOLOv5模型識別出組件類型和位置,以及百度通用OCR接口識別出文字內容與位置后,通過n元組生成算法生成組件名稱與選項的對應關系。考慮到組件與文字的位置關系包含相鄰關系和包含關系,算法中以組件位置為基準,分別進行向左匹配獲取組件名稱和內部匹配獲取選項名稱。以上思路是理想情況下的實現思路,但是實際情況中會出現以下兩個問題:一是當組件名稱與選項距離過近時,OCR會將其識別為一個整體;二是OCR存在一定誤差,文字中存在特殊字符,將多選框的方框、單選框的圓圈等包含在內。 n元組生成算法如算法2所示。首先進行向左匹配,針對每個YOLOv5模型識別出的組件,遍歷OCR識別出的文字信息列表,若存在一個文字框位于組件框左側距離不大于50,且文字框上下邊界位于組件框上下邊界之間,則判斷該文字為該組件的組件名稱(見算法2中的第4~6行)。然后進行內部匹配,如果文字框位于組件框的內部,則認為該文字為組件的選項或者是交互的數據,將其添加至組件名稱的后面(見算法2中的第8~10行)。針對問題一中的情況,文字框框與組件框相交,如果組件名稱還未匹配到則添加到列表的開頭位置,如果組件名稱已經存在則添加至組件名稱后面(見算法2中的第11~16行)。針對問題二中的情況,通過自定義函數remove(n)將n元組中的特殊字符去除(見算法2中的第17行)。 算法2:生成n元組算法。 Input:頁面中元素信息列表,頁面中文字信息列表 Output: n元組列表 1. def generate(yolov_infors, ocr_infors): 2. for yolov5_info in yolov_infors: 3. for ocr_info in ocr_infors: 4. if 0 <= yolov5_info.x1 - ocr_info.x2 <= 50 and ocr_info.y1 >= yolov5_info.y1 and 5. yolov5_info.y2 >= ocr_info.y2 6. n.append(ocr_info.word) 7. label= true 8. if yolov5_info.x1 <= ocr_info.x1 and yolov5_info.x2 >= ocr_info.x2 and 9. ocr_info.y1 >= yolov5_info.y1 and yolov5_info.y2 >= ocr_info.y2 10. n.append(ocr_info.word) 11. if (ocr_info.x1 12. ocr_info.y1 >= yolov5_info.y1 and yolov5_info.y2 >= ocr_info.y2 13. if label: 14. n.insert(1,ocr_info.word) 15. else: 16. n.insert(0,ocr_info.word) 17. n= remove(n) 18. list.append(n) 19. return list 自動生成測試序列以后,需要把測試序列自動轉化為文本測試用例。該文通過自定義規則集對測試序列中的測試信息進行排列,進而生成文字描述形式的測試用例: (1)IF 組件名稱為Input‖TextArea‖Radio‖CheckBox‖Select‖Date‖Upload‖InputNumber THEN組件名稱+交互動作+交互數據。 (2)IF 組件類型為Button‖Switch THEN 交互動作+組件名稱。 在眾包測試過程中,眾測工人會提交大量質量參差不齊的測試用例報告,測試用例報告中存在大量冗余測試用例[15]。因此在保存測試用例時需要進行去重操作,減少冗余的測試用例。由于眾測工人測試水平不同,因此就算是測試步驟和測試數據完全相同的測試,測試工人書寫的測試用例依然具有差異性,這就增加了去重的難度。在測試步驟與測試數據相同的前提下,文中的測試用例自動生成工具可以生成規范統一的測試用例,解決了眾測中測試用例去重困難的問題。 文本測試用例在保存時,首先與數據庫中已有的測試用例進行對比,如果存在相同的測試用例則不再保存。為了評估眾測工人生成測試用例報告的質量和多樣性,該文提出了測試用例覆蓋率(Test Case Coverage,TCC),定義如下: (1) 其中,save_testcase代表眾測工人保存到數據庫的測試用例數量,record_testcase代表眾測工人錄制的測試記錄數量。測試用例覆蓋率越高,表示冗余測試用例越少,測試用例報告質量越高。 文本測試用例效果圖如圖5所示。 圖5 文本測試用例效果圖 由于錄制回放工具普遍存在兩個問題,一是操作步驟錄制不完整,二是生成的測試信息不完整。為了評估文中方法所實現測試工具的性能,提出了以下四個研究問題。 研究問題1:實現的測試用例自動生成工具是否支持不同技術開發的Web系統?對不同框架不同結構的Web系統是否適用? 研究問題2:實現的測試用例自動生成工具在測試步驟完整性上效果如何? 研究問題3:實現的測試用例自動生成工具在測試信息完整性上效果如何? 研究問題4:實現的測試用例自動生成工具在時間性能上效果如何?能否在較短的時間內將錄制數據轉化為測試用例? 針對問題1實驗對象為Gitee中5款不同技術開發的Web系統,其主要開發技術如表2所示。 實驗環境:操作系統為Windows10,CPU為Intel(R) Core(TM) i7-10875H @ 2.30 GHz,GPU為RTX 2070 Ti 8G,運行內存16G,模型訓練框架為Pytorch,使用CUDA并行計算框架并配合CuDNN來加速網絡模型訓練。 表2 被測Web系統詳情 實驗過程中招募5名眾測人員進行測試。選取了三款不同的最新版本的錄制回放測試工具,分別是UFT 15.0.2,Selenium IDE 3.17.2,Katalon Recorder 5.9.0,與該文實現的工具進行實驗對比。針對問題2,使用平均操作覆蓋率(AOCR)來衡量不同測試工具對眾測工人測試記錄的覆蓋率: (2) 其中,n代表眾測工人的數量,record_operations代表測試工具生成的正確操作集合,real_operations代表執行測試任務時眾測工人的實際操作集合。被測系統的平均操作覆蓋率如圖6所示。 圖6 平均操作覆蓋率 實驗結果顯示,在ElementUI框架開發的Web系統中文中工具在測試步驟完整性方面要優于其他測試工具。實驗過程中發現UFT,Selenium IDE,Katalon Reconder無法有效定位富文本編輯器插件以及獲取其交互數據,導致在被測試系統學之思在線考試系統中錄制的正確步驟較少;UFT無法成功定位日期選擇框、級聯選擇器以及獲取其交互數據,Selenium IDE,Katalon Reconder無法成功獲取文件上傳的有關信息,在日期框交互次數較多的情況下,會出現獲取交互數據不準確的情況;在傳統的前后端一體的Web系統上(TAMLL天貓、青鋒管理平臺),文中工具在獲取測試步驟中要差于其他測試工具,主要原因是前端頁面中的大量組件都是通過JavaScript渲染生成,測試人員的某些操作會導致錄制數據中出現部分無規則數據,進而導致文中工具在獲取組件名稱時出現錯誤,不過n元組算法在TAMLL天貓系統中發揮了重大作用,將添加產品功能的步驟覆蓋率提高了29%。 針對問題3,在已經生成的正確的測試步驟前提下,為了評估工具生成測試用例的信息完整性,包括組件名稱、組件類型、交互數據和交互動作,提出了平均測試信息覆蓋率: (3) 其中,gen_testInfo代表工具生成的每個測試步驟中的測試信息數量,exp_testInfo代表期望的測試信息數量,m代表測試用例中的測試步驟數量,n代表眾測工人的數量。被測系統的平均測試信息覆蓋率如表3所示。 表3 平均測試信息覆蓋率 % 實驗結果顯示,文中工具的平均測試信息覆蓋率達到100%,生成的測試用例中包含了組件名稱、組件類型、交互動作和交互數據,證明了文中方法生成的測試用例具有很高的信息完整性。實驗過程中發現UFT生成的測試用例中缺少大部分組件的名稱,只有少數組件可以獲取到組件名稱,如按鈕,UFT也可以獲取組件中的默認值作為組件名稱。UFT是基于對象庫的錄制方式,可以間接獲取大部分組件的組件類型,因此UFT的平均測試信息覆蓋率要高于其他兩款測試工具。 Katalon Reconder生成的測試用例中缺少組件名稱,部分組件缺少交互數據,如下拉框,日期框,單、多選框等。在組件屬性不存在id的時候,Katalon Reconder通過優先級較高的XPath進行定位,可以間接獲取組件類型,Selenium IDE通過優先級較高的CSS進行定位,因此在Vue架構下的Web系統中,Katalon Reconder的測試信息覆蓋率要高于Selenium IDE的測試信息覆蓋率。Selenium IDE生成的測試用例缺少組件名稱、組件類型,部分組件缺少交互數據,如下拉框,日期框,單、多選框等。 針對問題4,該文統計了在不同被測系統上錄制數據轉化為測試用例的平均時間,如圖7所示。 圖7 轉換為測試用例的平均時間 實驗結果顯示在前四個系統上錄制數據自動轉化為測試用例的時間最多不超過4秒,但是在青鋒管理平臺時間較長,通過對錄制數據進行分析發現,該系統基于LayUI框架開發,具有豐富的彈框組件,且該系統存在大量JavaScript渲染的頁面,導致錄制數據中出現較多的動態節點樹,因此在測試信息搜索過程中花費了大量時間。 該文研究了眾測背景下測試用例自動生成的問題,提出了一種基于眾測工人測試記錄自動生成規范測試用例的方法,并實現了該工具。這是一款真正無代碼化的測試工具,更加適合沒有編程能力的眾測工人,降低了眾測的門檻,提高了測試效率。實驗結果表明,該方法能夠獲取較高的平均操作覆蓋率,平均測試信息覆蓋率達到百分之百,生成的測試用例信息更加完整。
2.3 測試信息修改


2.4 文本測試用例

3 實驗分析
3.1 實驗對象
3.2 實驗結果




4 結束語