AppFlow:使用機器學習來合成健壯的、可重複使用的 UI 測試

AppFlow:使用機器學習來合成健壯的、可重複使用的 UI 測試

摘要

眾所周知,UI 測試是非常困難的,尤其是在現在這種開發週期越來越快的情況下。手動 UI 測試非常繁瑣、昂貴且容易出錯。而自動化的 UI 測試在編寫和維護上成本又很高。

本文介紹了 AppFlow,一個用於合成高度健壯、高度可重用的 UI 測試的系統。它利用機器學習來自動識別常見的屏幕和控件,從而使開發人員不必編寫臨時的代碼邏輯即可在測試中使用它們。它使開發人員能夠為某類應用的主要功能編寫模塊化的測試庫(例如,針對購物應用的“添加到購物車”功能進行測試)。然後,它可以通過合成庫中的測試腳本,從而快速測試同一類別中的新應用。通過專注於特定類型應用的主要功能模塊,AppFlow 幾乎不需要人工干預。

我們在購物和新聞類別中的 60 個主流 app 上進行了評估,其中,我們對 BBC 和 JackThreads 應用分別進行了案例研究,對 Wish 應用中的 15 個主題進行了用戶調研。結果表明,AppFlow 可以準確識別屏幕和控件,合成高度健壯且可重複使用的測試。AppFlow 合成的測試覆蓋了 Jackthreads 中 46.6%的自動化測試,並將測試新應用的工作減少了 90%。有趣的是,儘管所有被測 app 都已公開發布並稱通過了全面測試但我們依舊發現了八個錯誤,包括七個功能錯誤。

1 介紹

大多數應用程序旨在與人類進行交互,因此測試 app 的功能、性能和用戶界面(UI)相關的其他關鍵方面至關重要。但是,眾所周知,UI 測試極具挑戰性。手動測試的優點是可以測試真實的用戶體驗,但是缺點是操作繁瑣,成本高且容易出錯。自動化測試原本應該是一種更好的替代方法,但是當今行業中的自動化測試需要大量的開發人員輔助,而且很少有公司具備進行自動化測試的技能或資源。

UI 自動化測試通常是基於腳本的測試。要進行自動化測試,開發人員必須投入高昂的初始成本來編寫測試腳本以及在應用程序 UI 更新時維護測試腳本。雖然這些任務從表面上看似乎很容易,但是由於應用程序 UI 是為人類智能而設計的,而測試腳本卻是低級的單擊單擊腳本,因此存在很多難以實現的功能。例如,向購物車添加商品的按鈕無論是“添加”字樣、加號或是圖標,我們人類都可以很容易地識別出,但測試腳本通常是通過開發人員提供的座標來定位按鈕。例如,當按鈕從“添加”字樣演變為圖標時,或者座標因屏幕尺寸等設備因素而不同時,這種識別方式很容易變得不正確。測試的錄製和重播減少了編寫測試的成本,但是錄製的測試很少能立即可用,UI 的更新將導致測試的重新錄製。

當今越來越快的開發週期加劇了自動化測試的挑戰。然而不幸的是,現有的自動化測試框架中很少有旨在跨 app 重用測試腳本的。首先,儘管相同類別的應用程序在流程上有很多相似之處,但它們的屏幕和控件可能具有截然不同的設計。因此,一個應用程序的測試腳本通常無法找到另一個應用程序的控件。其次,相同類別的應用程序可能仍然具有不同的流。例如,一個應用程序的登錄流程可能只包含登錄屏幕,而另一個應用程序可能首先顯示歡迎屏幕。一個應用程序的“添加到購物車”流程可能要求用戶首先訪問商品詳細信息屏幕,但另一個應用程序可能允許用戶將搜索結果中的商品直接添加到購物車。這些細微的差異會阻止在不同應用程序上直接重用測試腳本。

本文介紹了 AppFlow,這是一個用於合成高度健壯、高度可重用的 UI 測試的系統。它使開發人員能夠為特定類別的應用編寫模塊化的 UI 測試庫。該庫可以是開源共享的,也可以是存儲在測試雲服務中的。然後,當開發人員想要測試同一類別中的新應用時,他可以快速從庫中的模塊化測試中合成一個完整的測試,從而極大地提高了生產率。

通過專注於應用的主要功能,AppFlow 可以提供冒煙測試或是為源代碼的更改構建驗證測試,則幾乎不需要任何手工工作。先前的工作表明,這種測試,即使是不完整的測試,也可以為開發人員提供快速反饋,並幫助他們在 bug 產生更大影響之前及早修復 bug。開發人員可以選擇自定義 AppFlow 以添加針對特定應用的測試或覆蓋默認值以執行完整的迴歸測試。

AppFlow 中的一個關鍵思想是一種用於識別屏幕和控件的機器學習方法。AppFlow 不依賴開發人員的代碼邏輯,而是通過訓練集訓練分類器,訓練集包括帶標註的屏幕及控件。訓練集可以來自開發人員社區,並且 AppFlow 提供了多個實際程序來簡化這種一次性的數據收集。訓練分類器後,AppFlow 使用它來將變化的屏幕和控件映射到規範的屏幕和控件。例如,它將登錄屏幕上帶有“用戶名”、“您的電子郵件”或“[email protected]”的文本編輯框都映射到代表用戶名控件的 signin.username。這種機器學習方法使 AppFlow 測試可以引用規範的屏幕和控件,而不是針對特定應用程序的屏幕和控件,因此具有很多優點。首先,只要新的 UI 界面可以被 AppFlow 識別,app 的 UI 就可以不斷更新而不會破壞測試腳本。其次,應用程序用戶界面可以適應各種設備因素(例如屏幕尺寸)而不會破壞測試。第三,規範的屏幕和控件實現了對應用程序的抽象,從而使跨應用程序共享測試變得容易。第四,AppFlow 能夠識別屏幕,從而使開發人員能夠專注於測試屏幕的特定流程,而無需編寫太多代碼來啟動 app,或在測試結束後將應用程序恢復到以前的狀態。這點對於可重用性起著至關重要的作用。

AppFlow 的第二個主要思想是通過可重複使用的獨立測試來發現應用的行為,並從中合成完整的測試。我們將可重複使用的獨立測試稱之為“流”。為了測試諸如“在商品詳細信息頁面上,用戶可以將商品添加到購物車”之類的功能,開發人員編寫了包含以下三個組成部分的流程:(1)測試的前提條件,例如“應用程序必須在商品上詳細信息屏幕;”(2)測試的後置條件,例如“應用程序必須在購物車屏幕上”;(3)進行測試的實際步驟,例如單擊“添加”按鈕。前提條件和後置條件在本質上類似於霍爾邏輯,並且可以在應用程序狀態上包含自定義條件,例如 loginin = true(即用戶必須已登錄)。“流”具有雙重用途:可用於測試應用程序是否正確實現了此功能,並且可用於將應用程序導航到測試其他功能所需的狀態。具體來說,在給定一個流庫的情況下,AppFlow 會動態合成以下完整的測試:啟動應用程序,識別其狀態,找到滿足先決條件的激活流,執行每個流,併為到達的每個新狀態重複以上步驟。

AppFlow 的合成方式有兩個主要好處。首先,它極大地簡化了測試的創建,因為開發人員不再需要編寫特定代碼來將應用程序置於特定狀態或隨後清除該狀態。其次,模塊化可實現測試重用。如果將測試指定為一個整體,則由於測試對象場景或是實現該場景所需步驟的變化,測試將幾乎無法重用。相比之下,模塊化測試可以通過適當地合併以適應特定應用的行為。例如,我們可以創建一個測試庫,其中包含兩個帶有或不帶有歡迎屏幕的登錄流程以及兩個通過或不通過商品詳細信息屏幕的購物車流程。然後,AppFlow 可以為我們要測試的新購物應用程序合成出正確的測試。此外,它還允許 AppFlow 適應應用程序行為的更改。AppFlow 可以發現應用程序的新行為,並自動為它們和完成相應的測試。

由於 Android 平臺的廣泛採用和開發人員面臨的嚴峻市場競爭,我們為 Android 平臺實施了 AppFlow,但是這些想法和技術很容易應用於一般的 UI 測試。AppFlow 編寫流程的語言是 Gherkin 的擴展,Gherkin 是一種人類可讀的領域特定語言,用於描述應用程序行為。

我們對 AppFlow 進行了四組實驗。首先,我們為兩個應用類別創建了測試庫,並對 40 個購物應用和 20 個新聞應用進行了評估。其次,我們對 BBC 新聞應用程序進行了案例研究,該應用程序具有兩個截然不同的版本,通過實驗驗證 AppFlow 合成的測試是否對更改具有魯棒性。第三,我們對 Wish 的 15 個主題進行了一項用戶研究,以比較 AppFlow 和現有測試框架。第四,我們分析了 JackThreads 應用程序開發人員的手動測試計劃,並量化了 AppFlow 可以自動合成的測試數量。結果表明,AppFlow 可以準確識別屏幕和控件,合成高度健壯和可重複使用的測試,涵蓋所有針對 Jackthreads 的自動測試的 46.6%,並將測試新應用的工作減少了 90%。有趣的是,儘管所有被測 app 都已公開發布並稱通過了全面測試但我們依舊發現了八個錯誤,包括七個功能錯誤。

本文做出了三個主要貢獻:(1)用於合成高度健壯、高度可重用的測試的 AppFlow 系統;(2)我們的技術利用機器學習來識別屏幕和控件的魯棒性和可重用性;(3)我們對 60 個購物和新聞應用程序進行了評估,這些應用程序產生了 2944 個測試並發現了 8 個錯誤。AppFlow 的源代碼和測試庫可在 github.com/columbia/appflow 中找到;AppFlow 的數據集可在 github.com/columbia/appflow-dataset 上獲得。

AppFlow:使用機器學習來合成健壯的、可重複使用的 UI 測試

Figure 1: 流程:“添加到購物車”。

2 綜述

本節首先提供一個簡潔的示例,以演示如何編寫 AppFlow 測試,然後描述其工作流程。

2.1 例子

假設開發人員想測試購物應用程序的流程“向空購物車中添加商品會清除“購物車為空”消息”。圖 1 顯示了 AppFlow 中此測試的示例。流程的前提條件已給出。激活此流程的屏幕應該是“詳細信息”屏幕,這是顯示項目詳細信息的規範屏幕。此屏幕幾乎存在於所有購物應用程序中,因此使用它指定條件不僅可以簡化對該流程的理解,還可以在其他購物應用程序上重用此流程。這裡的“屏幕”是 AppFlow 內置的可見屬性。為了運行此流程,AppFlow 確保必須滿足流程的前提條件,即前提條件中指定的所有屬性都必須具有相應的值。

接下來,該流程相應按鈕進行了兩次單擊。與使用手寫的的傳統測試腳本不同,AppFlow 測試使用由測試庫導出的規範組件,且 AppFlow 利用機器學習將實際組件與規範組件進行匹配。

這個簡單的示例顯示了 AppFlow 的一些關鍵優勢。即使對於非開發人員(例如產品經理),此流程也易於理解。AppFlow 會使用機器學習方法自動識別所使用的規範屏幕和控件,從而使測試對 UI 設計的更改具有魯棒性,並且可在不同應用程序之間重複使用。該系統允許開發人員僅描述要測試的流程,而無需編寫樣板代碼將應用程序帶到項目詳細信息屏幕。

2.2 工作流程

圖 2 顯示了 AppFlow 的工作流程。它分為兩個階段:第一階段(通常是一次),為新類別的應用程序做準備,第二階段,應用 AppFlow 來測試該類別中的每個新應用程序。

AppFlow:使用機器學習來合成健壯的、可重複使用的 UI 測試

Figure 2: AppFlow 的工作流程。此處的簡筆圖代表開發人員的干預。

2.2.1 為新的應用類別做準備

首先,他們使用 AppFlow 創建一個測試庫,其中包含該類別的通用流程,並在此過程中定義規範的屏幕和控件。其次,他們使用簡單的實用程序來捕獲規範屏幕和控件的數據集並對其進行標記。有時,不同類別的應用程序共享相似的屏幕(例如,登錄屏幕),也可以添加其他應用程序類別的這些示例。有了這個數據集,

AppFlow 將從每個樣本中提取關鍵特徵,並訓練分類器。

2.2.2 測試一個新的應用程序

為了測試新應用,開發人員要做兩件事。首先,他們為應用程序定製測試庫。機器學習無法始終識別每個規範的屏幕和控件, 為了糾正偶然的錯誤,開發人員運行 AppFlow 來發現機器學習中存在的錯誤並覆蓋它們。此外,開發人員還為庫中使用的變量提供值,例如測試用戶名和密碼。開發人員還可以添加自定義流程來測試特定於應用程序的行為。

其次,開發人員在應用程序上運行 AppFlow 來記錄初始測試結果。測試庫通常包含多個變體流程,例如從歡迎屏幕或菜單屏幕登錄。AppFlow 運行所有流並報告每個流的結果,讓開發人員確認哪些流應該成功,哪些流應該失敗。

完成這兩個設置步驟後,開發人員可以定期測試新版本的應用程序是否存在迴歸。AppFlow 運行類似的過程來為每個新的應用程序版本合成完整測試,並將結果與上次運行的結果進行比較。

3 識別規範的屏幕和控件

直觀地講,用於類似目的的屏幕和控件應具有相似的外觀,並具有相似的名稱。但是,由於跨應用程序的差異以及同一應用程序隨時間的演變,簡單的規則無法正確識別它們。例如,“登錄”屏幕上的“登錄”按鈕可能包含“登錄”、“讓我登錄”,甚至是顯示箭頭的圖標。基礎 UI 對象通常具有“Button”的類名,但是有時可以將其更改為“TextView”甚至“RelativeLayout”。AppFlow 無需使用臨時的手動編寫規則來識別控件,而是利用機器學習組合各個來源的信息,因此功能更加強大。

特徵選擇是準確識別的關鍵,它佔用了我們很多精力。我們嘗試了多種功能組合,並通過以下方法進行了解決。對於每個 UI 對象,識別的特性包括其關鍵屬性,例如描述文本,大小,是否可單擊。在最終特徵向量中,所有特徵都將轉換為 0 到 1 之間的值。使用最大值對大小等數字特徵進行歸一化。布爾功能(例如,控件是否可單擊)將直接轉換為 0 或 1。UI 佈局通過預定樹遍歷轉換為文本。圖形特徵以兩種方式處理。按鈕圖標具有特定含義,因此可以通過計算其定向梯度的直方圖將它們轉換為特徵向量。其他圖形功能可通過 OCR 轉換為文本。所有文本功能(包括從 UI 佈局和圖形轉換而來的文本功能)均使用術語頻率-反向文檔頻率進行轉換。直觀地講,如果術語出現在更少的文檔中,而在文檔中出現的次數更多,那麼其權重則更高。

4 編寫測試流程

本節首先描述我們對 Gherkin 語言所進行的擴展,然後說明有關創建測試庫的一些細節。

4.1 編寫流程的語言

AppFlow 所使用的流程語言遵循 Gherkin 的語法。Gherkin 是由行為驅動的開發工具 cucumber 使用的需求描述語言。而 cucumber 被廣泛用於移動應用程序的自動化測試框架 Calabash 中,因此,我們選擇擴展 Gherkin 而不是擴展另一種語言,因為移動開發人員應該已經對此有所瞭解。

在 AppFlow 中,每個流都被編寫為 Gherkin 中的場景,其中先決條件以 Given 為前綴,測試步驟以 When 為前綴,後置條件和效果以 Then 為前綴。與 Gherkin 中使用自然語言作為條件和步驟的應用程序不同,AppFlow 使用可見的和抽象的屬性。

下面我們顯示了四個流程示例。第一個流程測試用戶可以使用正確的憑據登錄:

AppFlow:使用機器學習來合成健壯的、可重複使用的 UI 測試

第二個流程測試登錄用戶是否可以從主屏幕進入購物車:

AppFlow:使用機器學習來合成健壯的、可重複使用的 UI 測試

當購物車為空時,第三個流程測試“購物車為空”消息是否顯示在“購物車”屏幕上:

AppFlow:使用機器學習來合成健壯的、可重複使用的 UI 測試

最後一個流程要求當購物車為非空時,將購物車清空,並期望看到“購物車為空”消息:

AppFlow:使用機器學習來合成健壯的、可重複使用的 UI 測試

4.2 創建測試庫

如今,開發人員為同一類別中的不同應用程序編寫了類似的測試用例,導出產生了大量的多餘工作。通過測試庫以及 AppFlow 能夠識別規範屏幕和控件的功能,開發人員可以共享他們的工作,從而大大提高了生產率。

為測試庫編寫流程有兩個注意之處。首先,開發人員需要確定要在測試庫中包含多少個流。在創建定製流的成本和創建定製的成本之間需要權衡。包含更多的流,測試庫就更有可能包含罕見的測試行為,因此需要的自定義流也更少。另一方面,包含更多的流通常意味著更罕見的控件,這些控件的應用樣本更少。因此,這些部件可能具有較低的分類精度,這使得它們需要更多時間來進行自定義。其次,相同的功能在各個應用程序之間的實現可能略有不同。如前所述,一個應用程序的添加到購物車流程可能要求用戶首先訪問商品詳細信息屏幕,但是另一個應用程序可能允許用戶將搜索結果中的商品直接添加到購物車。儘管從概念上講這些流程是對購物車添加功能的相同測試,但是它們需要以不同的方式實現。因此,AppFlow 支持可以具有多個變體流程的測試。

5 將測試庫應用到新應用

開發人員分兩個階段將測試庫應用於其應用程序。首先,在設置階段,當第一次將測試庫應用到應用程序時,需要配置並自定義測試庫,特別是為測試變量分配必要的值。開發人員也可以在此階段添加自定義流程,以測試特定的應用行為。之後,運行 AppFlow 來合成測試並記錄通過和失敗的結果。請注意,失敗的流並不一定表示錯誤。相同的功能可能以不同的方式實現,因此失敗的流程可能只是意味著它不適用於需要被測試的應用。

其次,在增量階段,應用該測試庫來測試應用程序的新版本。具體來說,AppFlow 在新版本上運行針對先前版本合成的所有測試,重試先前失敗的所有流,並將結果與先前結果進行比較。差異可能表現在一些先前通過的流現在失敗,而其他先前失敗的流現在通過。然後,開發人員可以修復錯誤或確認要進行某些更改。如果需要,可以進一步自定義庫。每次增量運行所需的時間都比設置階段要少得多,因為 AppFlow 會記住為先前版本合成的測試。

AppFlow 從應用程序的初始狀態開始,重複執行測試流,並使用這些流達到的新狀態擴展狀態轉換圖。當不再有活動流時,該過程結束。通過組合從初始狀態開始到結束的流鏈,可以對流進行全面測試。

6 實現

AppFlow 使用 15979 行 Python 代碼為 Android 平臺實現。它使用 scikit-learn 進行機器學習,並使用 Tesseract 從圖像中提取文本。

6.1 捕獲屏幕布局

AppFlow 使用 UIAutomator 捕獲當前的屏幕布局。AppFlow 還通過 WebView 遠程調試協議與應用程序的 WebView 進行通信來捕獲應用程序的嵌入式網頁。與 UIAutomator 相比,嵌入式網頁內的控件提供了更多詳細信息。

6.2 捕獲佈局後的處理

UIAutomator 返回的佈局包含多餘或不可見的視圖,這會降低 AppFlow 的屏幕和控件識別的準確性。因此, AppFlow 使用多種轉換對佈局進行處理。例如,將一個僅帶有單個孩子節點的容器刪除,只保留其孩子節點。另一種轉換是使用光學文本識別來查找和刪除隱藏的視圖。它從每個控件的快照中提取文本,並將該文本與控件的 text 屬性進行比較。如果差異太大,則將該部件標記為不可見。如果控件的所有子級都不可見,則 AppFlow 還將控件也標記為不可見。我們的結果表明,這種處理可以安全地刪除多達 11.5%的控件。

7 侷限性和未來工作

7.1 AppFlow 本身的限制

AppFlow 旨在大大減少進行自動化 UI 測試的人工工作,但 AppFlow 尚未能完全替代手動 UI 測試:眾所周知,到目前為止,由於用戶體驗非常主觀,因此自動化 UI 測試無法完全替代手動 UI 測試。但是,早期發現應用中存在的錯誤可以提高開發人員的生產力和軟件質量,從而間接減少手動測試的工作量。

因此,AppFlow 旨在生成常見的自動測試方案。因此,測試庫應僅包括通用流,而不是每個可能的流。可以編寫自定義流程來測試特定應用程序的功能。另一方面,必須有足夠的自定義流或通用流,才能使 AppFlow 合成可執行測試。例如,如果沒有適用的登錄流程,則 AppFlow 無法到達要求用戶登錄的流程。我們的評估顯示,通常僅需要少量的自定義流程。

AppFlow 的測試庫中的流程應僅引用規範的控件,這可能會限制其執行的檢查並降低其有效性。AppFlow 專注於測試核心功能,正如我們已經顯示的那樣,這些功能在應用之間廣泛共享,並且只能使用規範的控件進行測試。隨著測試庫的發展,可以添加更多的規範屏幕,並且可以定義更多的規範控件,因此測試可以更加有效。

7.2 機器學習中的分類錯誤

AppFlow 利用機器學習來識別屏幕和控件。由於本質上是統計的,因此機器學習有時會產生錯誤,從而需要開發人員提供匹配器。當應用程序更新時,這些匹配器也可能需要更新。即使測試的功能未正確實現,流也可能通過。例如,假設一個流程檢查了某個規範的控件,並且軟件更新刪除了該控件,則如果機器學習錯誤地將另一個控件識別為規範控件,則該流程仍然可以通過。機器學習分類錯誤只會導致最簡單的流程出現問題,因為依賴於與該控件交互的任何流程都可能會中斷,從而向開發人員指出了問題。但是,此問題不僅限於 AppFlow,因為傳統的測試腳本通常使用脆弱的規則來匹配控件,因此它們具有相同的問題。相反,由於 AppFlow 使用機器學習來識別規範的 UI 元素,因此隨著機器學習的準確性提高,此問題也將得到緩解。

8 總結

在本文中,我們介紹了 AppFlow,這是一個用於合成高度健壯、高度可重用的 UI 測試的系統。AppFlow 通過識別同一類別中的應用程序具有的共同點來實現這一目標。它利用機器學習來識別規範的屏幕和控件,並提供了一種用於從模塊化測試庫中合成完整測試的系統。

我們在購物和新聞類別中的 60 個流行應用程序上評估了 AppFlow,其中,在 BBC 新聞應用程序和

JackThreads 購物應用程序中進行了兩個案例研究,在 Wish 購物應用程序中對 15 個主題進行了用戶研究。

結果表明,AppFlow 可以準確識別屏幕和控件,合成高度健壯且可重複使用的測試。其合成的測試覆蓋了 Jackthreads 中所有自動化測試的 46.6%,並將測試新應用的工作減少了 90%。我們還在評估中發現了 8 個錯誤,其中有 7 個是功能錯誤,包含這些錯誤的應用程序已公開發布並且應該進行了全面的測試。

致謝

本文由南京大學軟件學院 2020 級碩士生張松濤翻譯轉述

感謝國家重點研發計劃(2018YFB1003900)和國家自然科學基金(61832009,61932012)支持!


分享到:


相關文章: