佘學文 陳向宇 劉東啟
1(廣東嶺南職業技術學院 廣東 廣州 510663) 2(華南理工大學計算機科學與工程學院 廣東 廣州 510006)
隨著人工智能和移動互聯網的迅猛發展,智能手機已經成為人們生活的重要部分。美國媒體機構Zenith發布的最新研究報告顯示, 2018年中國智能手機用戶數達到13億,位居全球第一,全球智能手機用戶數也達到33億,并且還在逐年增加。圖形用戶界面(Graphical User Interface,GUI)是用戶與手機應用程序(App)進行交互的最重要通道。在激烈的市場競爭中,高質量、無瑕疵的GUI是一款應用程序成功的重要前提,GUI測試是保證應用程序GUI質量的重要手段。目前,學術界和工業界已經研究、實現和評估了多種GUI測試的方法[1-6],但Joorabchi等[7]一項關于移動App開發面臨的挑戰的研究表明,超過70%的移動應用開發或測試人員在實踐中傾向于采用手動方法進行GUI測試,從事全自動GUI測試的人數不到5%,超過一半的參與者認為實現自動化GUI測試是一項具有挑戰性的工作,且移動應用GUI測試目前仍然是一項勞動密集型工作。
為了提高Android應用GUI測試的效率和自動化水平,本文建立一套易于實現、開展測試的前置條件簡單且更加高效的Android應用GUI自動化隨機測試方法,該方法在開展測試前只需要簡單的準備工作,同時采用以下手段來保證更好的代碼覆蓋率:
1) 在測試時通過映射GUI樹和行為樹模型來避免靜態分析。
2) 動態更新模型以增加用戶在使用應用程序過程中很少或從未使用過的事件的概率。
3) 應用統計模型建立行為樹模型。
目前,工業界和學術界已經在Android應用GUI自動化測試方面開展了許多工作。Google提供的Android SDK中,給出了三種可用于自動化測試的方式,即Monkey、MonkeyRunner和Instrumentation。其中Monkey[3]是測試Android應用程序最常用的工具,它通過向系統發送偽隨機的用戶事件流(如按鍵輸入、觸摸屏輸入、手勢輸入等)對被測應用程序(Application Under Test ,AUT)進行有效的自動化測試。但Monkey自動生成的大量輸入很簡單,無法生成需要人類智能組合的測試輸入,且會生成很多冗余輸入。文獻[4-5]采用了基于Hook機制的GUI自動化測試方法。文獻[8]采用的基于隨機探索的方法。文獻[9]采用了基于模型(MBT)的方法并研制了工具AndroidRipper。該工具維護一個GUI狀態機模型,在執行測試過程中,AndroidRipper通過深度優先搜索(DFS)策略動態分析GUI的控件獲取其可觸發的事件序列,每一個事件序列就是一個測試用例。文獻[10-11]提出基于捕獲用戶輸入的GUI自動化測方法,其中文獻[11]創建了一個名為MonkeyLab的工具,該工具通過挖掘GUI的模型為自然和非自然事件序列生成可操作的場景。
本文提出的基于行為樹模型的GUI自動化隨機測試方法的創新之處在于開展測試的前置準備過程簡單,且測試過程中會動態更新行為樹模型以增加測試覆蓋率。初始行為樹模型是通過統計建模從使用日志中創建的,考慮到Android應用的部分事件可能在使用日志中沒有出現過,提出通過將行為樹模型中的事件映射到GUI樹中的控件來解決,同時行為樹模型中事件的概率也隨著測試的進行而動態調整。圖1為本文方法的總體框架,主要分為六個步驟。

圖1 方法總體框架
1) 從使用記錄器中預先收集使用日志,并利用Hierarchy Viewer從AUT中提取GUI樹。
2) 應用統計模型創建行為樹模型,然后將行為樹模型中的事件映射到GUI樹中的控件,以便根據要執行事件序列,自動進行GUI控件操作,實現GUI的自動化測試。
3) 從行為樹模型中隨機選擇事件,生成執行事件序列。
4) 將所選事件觸發到AUT。
5) 對使用日志進行日志分析,根據分析結果得到用戶執行某事件的頻率,并根據事件頻率調整概率,動態更新行為樹模型。
6) 重復步驟2)至步驟5)直到達到時間限制或預先確定的事件數量。
此步驟的目的是獲取用于生成行為樹模型的控件、使用日志和GUI樹。
2.1.1使用日志獲取
獲取使用日志是本文方法開展測試的唯一前置條件和步驟。使用日志是通過使用記錄服務Recorder從AUT獲得的。Recorder服務使用Android的AcciblityService實現,該服務以AccessibilityEvent的形式捕獲測試人員或用戶執行的事件,然后收集這些事件并通過Android調試橋(Android Debug Bridge,ADB)傳輸到Observer。如表1所示的事件,如果Recorder服務開啟,那么一旦用戶開始使用應用程序,Recorder服務就會記錄用戶的使用日志,直到用戶關閉該應用程序。由于這些使用日志是建立行為樹模型的基礎,因此覆蓋的使用場景越多越好,測試方可以通過眾包的方式獲得大量使用日志數據。

表1 AccessibilityEvent定義的幾種事件類型

續表1
2.1.2從AUT中提取GUI樹
GUI樹是GUI控件的層次結構,在運行時使用Android SDK工具包中的可視化調試工具Hierarchy Viewer從AUT中提取。Hierarchy Viewer 通過ADB與 Android 模擬器或 Android 真機進行通信,可以列出應用程序的樹形結構布局,并提供所有 GUI 控件的ID、控件類型、文本內容、位置和大小等信息。本文使用圖2所示的圖片編輯程序來作為測試樣例進行說明,圖3顯示了圖2中示例活動的簡化GUI樹。在這個例子中,簡化的GUI樹包括6個GUI 控件:e1.backButton、e2.editButton、e3.deleteButton、e4.shareButton、e5.imageView和e6.saveButton 。

圖2 樣例AUT(圖片編輯程序)

圖3 AUT的GUI樹
在這個步驟中,根據使用日志創建行用戶執行事件的行為樹模型,然后將事件映射到GUI樹中的GUI 控件。
2.2.1行為樹模型生成
通過使用馬爾可夫假設近似條件概率從使用日志創建行為樹模型(如圖4中的簡化行為樹模型)。

圖4 簡化的行為樹模型
本文使用N-gram語言模型來實現,N-gram 是一種基于統計語言模型的算法,又被稱為一階馬爾可夫鏈,它的基本思想是將文本里面的內容按照單詞進行大小為N的滑動窗口操作,形成長度是N的單詞片段序列。在軟件測試的背景下,這些單詞代表事件,n表示事件的數量。例如,一系列事件etap1,etap2,ehold1,eswipeUp,如果設n=2,那么2-gram為:
1)p(etap2|etap1)
2)p(ehold.1|etap2)
3)p(eswipeUp|ehold.1)
如果設n=3,那么3-gram為:
1)p(ehold.1|[etap1,etap2])
2)p(eswipeUp|[etap2,ehold.1])
其中,p(ex|[ej,ek])是在給定歷史事件[ej,ek]下選擇事件ex的概率,當n較大時,模型可以存儲更多上下文,從而可以更加充分地進行時空權衡。在實際中,用戶的使用范圍可能無法完全覆蓋應用程序的所有功能。在圖4中,假設當用戶處于活動B時,可能發生另一個事件e6,但簡化的行為樹模型中沒有該事件,這意味著模型未對程序的事件實現完全覆蓋,且事件e6永遠不會被映射、選擇和執行。因此,將GUI樹中可用、但在模型中不存在的事件稱為未知事件。
為了解決這個問題,需要調整概率分布。常用的N-gram訓練工具有SRILM、IRSTLM、BerkeleyLM和KenLM等[12-14],這幾種工具所用的算法思想基本一致,本文以KenLM(速度最快,占用內存最少)作為訓練工具,所用的平滑技術是Modified Kneser-ney smoothing[15]。因為它被認為是當前一個標準的、廣泛采用的、效果最好的平滑算法,Modified Kneser-ney smoothing平滑技術有三個核心思想。
1) 絕對折扣。為了給未知事件一些概率,必須降低其他事件的概率,以保持有效的概率分布。
2) 插值。遞歸地組合所有k-gram的概率,其中k∈1,2,…,n,如果一個事件序列在模型中出現任何k-gram下標,那么它將產生非零概率。
3) 歷史。應該考慮每個事件出現的上下文的數量。例如,如果一個事件只發生在特定的上下文中,那么它就不太可能出現在新的上下文中。
2.2.2將行為樹模型映射到GUI樹
行為樹模型中的每個事件都使用唯一的resource-id作為鍵映射到GUI樹中的GUI控件,如果沒有定義resource-id,則使用類型和文本映射到GUI控件。為了提高查找速度,本文使用哈希表實現GUI映射器,并在每次重新獲取使用日志信息后進行更新。
本文的目的是測試應用程序,而不是創建一個自然的動作序列,因此,動作序列中的下一個事件并不會簡單地依據概率的高低選擇,而是隨機選擇。設e1,e2,…,en∈{possibleEvents},且h是先前選擇的歷史事件,事件選擇器將根據給定的一系列先前所選事件的平滑概率來隨機選擇enext:
enext=w([p(e1|h)],[p(e2|h)],…,
[p(en|h)])
(1)


圖5 平滑后的行為樹模型
Event Executor執行由事件選擇器在實際移動設備或仿真器上通過UI Automator選擇的enext,本文方法可以執行諸如單擊、長按、滾動和文本編輯等事件,這些事件定義如下:
單擊:點擊并立即在視圖中釋放。
長擊:在視圖點擊并按住3 s后釋放。
滾動:點擊并拖動到x+Δx,y+Δy位置。
文本編輯:輸入任意的預生成的字符串。
假設enext為圖4中的e6,并且是可點擊的,Event Executor將向視圖的中心觸發一個單擊事件,在這種情況下,本例中為saveButton。
執行后,利用偏置隨機技術對模型進行更新,以調整所選擇/執行的事件的概率,它減少了先前選擇和執行的事件的小因子。
p′(ex|h)=p(ex|h)-d(ex,δfx)
(2)
式中:fx是ex的頻率,d(ex,δfx)是ex的折扣值,p(ex|h)是給定歷史事件h下事件ex發生的概率。假設d(e6,δf6)=0.005,那么根據式(2)可以得到p′(e6|h)=0.025,在從ex中減少一些概率之后,必須重新計算每個p′的概率,以便通過將其除以總p′概率來保持有效的概率分布。
(3)
式(3)的結果如圖6所示。p(e6|h)的概率降低了,但p(e1|h)至p(e5|h)略有增加,這將使其他事件有更大的機會被選擇,從而提高代碼覆蓋率。最后,在執行e6后更新器更新行為樹模型。

圖6 更新后的行為樹模型
為了評估本文方法的有效性,將其與另外三種主流的方法進行比較:Android Monkey、手動測試和Dynodroid工具。評估采用的目標程序是三個未經修改的開源Android應用程序:Anymemo[16]、World Clock[17]和Weight Chart[18]。這三款工具分別具有動態內容、靜態內容和復雜的用戶界面,可以在一定程度上保證評估的覆蓋面和可信性。

表2 性能評估程序
所有的實驗都使用Android API 19在Nexus 5模擬器上完成的,該模擬器具有1 586 MB的RAM,運行在64位Windows 7計算機上,具有3.1 GHz的i7處理器和16 GB的RAM。讓5個學生分別使用5分鐘上述應用程序來獲取使用日志,對他們如何使用這些應用程序沒有任何限制,且每次實驗AUT都安裝在新創建的模擬器上,同時只使用默認設置。每一次實驗,根據本文方法開發的工具、Android Monkey和Dynodroid都包含5 000個觸摸事件,為了確保每次執行下一個事件之前完成屏幕切換或動畫,在每個事件之間設置500 ms的延時。對于手動測試,要求測試人員在40 min內盡可能多地手動執行這些應用程序。在每次實驗后都會重置模擬器以防止它影響后續的測試,同時使用EMMA覆蓋率檢測工具[19]和自定義shell腳本從AUT收集覆蓋率信息。
在每個程序設置了10個數據采集點,每500次事件間隔讀取一次代碼覆蓋率,測試結果如表3所示。Our_COV代表本文方法的覆蓋數據,Monkey_COV代表Android Monkey的覆蓋數據,Dynodroidy_COV代表Dynodroidy的覆蓋數據,Manual_COV代表人工手動測試的覆蓋數據,表中的數字表示每種方法所覆蓋的代碼行數和代碼覆蓋率。測試結果表明,在Anymemo中,本文方法的性能優于Android Monkey和Dynodroid,但是沒有手動測試好。在3個應用程序測試中,人工手動測試的代碼覆蓋率均是最高的,這是可以預見的,因為人類可以提供更智能的文本或順序輸入。

表3 四種測試方法代碼覆蓋率對比
圖7顯示了Anymemo的累積代碼覆蓋率。X軸表示基于500個事件間隔的事件數量。為了不在測試期間干擾受試者,在手動測試期間沒有記錄覆蓋率,所以手動測試的數據為最終覆蓋率。

圖7 Anymemo的累積代碼覆蓋率
本文介紹了一種基于行為樹模型的Android應用GUI自動化隨機測試方法。該方法基于實際使用日志創建行為樹模型,在運行時用GUI樹映射行為樹模型,用改進的Kneser-Ney平滑技術處理零概率未知事件。為了評價本文方法的有效性,設置了實驗,通過3個開源應用程序與Android Monkey、手動測試、Dynodroid等方法進行了對比。測試結果表明,本文方法在所有應用程序上都優于Android monkey,在Anymemo、World Clock上優于Dynodroid,但是落后于手動測試。未來,將擴展本文方法能夠處理的可操作事件,如縮放、拖拽等。同時通過更復雜的Android應用程序來評估本文提出的工具。