前面一篇文章實作了一個很簡單的 Android UI 自動化測試的 demo,接下來會分兩篇文章分别介紹下 uiautomator2 和 pytest 的使用,最後會結合兩者完成一個 Android UI 自動化測試的項目。此篇文章則主要介紹 uiautomator2。
連接配接手機
首先你要已經安裝了 uiautomator2,安裝指令是:
pip install uiautomator2
然後将已經開啟了開發者模式,且已允許調試的手機連接配接至電腦,然後運作以下指令:
python -m uiautomator2 init
上面代碼會在你手機上安裝兩個用于控制手機的 app,可以這樣說 uiautomator2 實作自動化操作手機主要就是依靠的這兩個 app。其實如果不運作以上代碼,在運作 u2.connect() 的時候也會自動進行初始化操作,提前初始化可以稍微縮短代碼運作時間。一般該操作在一台手機上運作一次即可。
接着我們需要建立一個 .py 檔案,寫入以下代碼:
import uiautomator2 as u2
# connect() 不傳入任何參數的話會預設連接配接 device list 内的第一台手機,當電腦連接配接有多台裝置時,
# 可以傳入指定裝置的 device id,如果裝置時通過 WiFi 進行連接配接的,則可以傳入裝置在網絡上的位址
d = u2.connect()
print(d.app_current())
啟動你手機上任意一個應用,運作以上代碼,正常情況下會輸出目前運作的這個應用的包名和程序。
如果前面的流程你都可以走通,那麼接下來就可以來使用代碼控制手機了,如果沒走通的話可以留言或私信我,也可以自己搜尋報錯資訊來找尋解決辦法。
操作手機
通過坐标點選
我們現在已經連上了手機,相當于我們已經手裡拿到了一台手機,如果我們要操作手機,我們肯定是要在手機螢幕上點選我們要點選的内容,我們就需要知道那個内容的坐标。那麼我們可以直接點選這個坐标,點選坐标可以使用
d.click(x, y) # x, y 可以是具體的坐标,也可以是坐标百分比
具體坐标的擷取可以使用 weditor,上一篇文章裡有安裝及使用方法。使用 weditor 加載出手機界面以後,滑鼠點選下需要點選的位置,在頁面中間有一行是點選位置的坐标,如圖。
weditor 顯示點選點坐标
滑鼠點選圖中标注①位置的方框,可以切換顯示具體坐标還是坐标百分比。由于安卓手機分辨率各式各樣并不統一,是以使用坐标百分比在一定程度上可以增加代碼的相容性,友善相同的代碼去操作不同型号的手機。
通過元素屬性點選
通過坐标點選來操作手機會特别不穩定。因為實際運作過程中,由于手機的網絡,性能等不确定因素,會造成我們的界面不能正常加載,而我們的代碼無法判斷界面是否已經加載出來,隻會順序的執行點選,造成腳本運作異常。
我們可以通過根據要點選的元素屬性定位元素,然後再點選,我們還可以設定定位這個元素的逾時時間,在這個時間内如果符合這個屬性的元素出現則點選或執行其它操作,如果沒出現則報錯。
uiautomator2 主要通過以下方式來定位元素:
隻列舉了主要的定位方式,不常用的未列舉。
- text,textContains,textMatches,textStartsWith
- resourceId,resourceIdMatches
- className,classNameMatches
上面三種屬性定位方式開頭都是精确比對,後面是模糊比對。
比如下圖中的發送按鈕:
短信發送界面
上面的發送按鈕我們可以用以下方式定位:
# text
d(text="發送")
# resourceId
d(resourceId="com.android.mms:id/send_button")
# className,由于界面上 className 相同的元素會特别多,是以此種定位方式用到的比較少
# 一般會作為輔助定位
d(className="android.widget.TextView")
# 多種方式結合,通過一種方式無法唯一定位到某個元素時可以多種方式結合
d(text="發送", resourceId="com.android.mms:id/send_button")
上面代碼隻是定位到了元素,也就是說通過執行上面任意一種定位方式的代碼,我們隻是找到了那個元素,如果要對該元素執行操作,則需要告訴腳本:
# 點選發送按鈕,逾時時間10秒,10秒内元素出現則點選,未出現報錯
d(resourceId="com.android.mms:id/send_button").click(timeout=10)
# 判斷發送按鈕是否出現,逾時時間為10秒,10秒内未出現該元素傳回 False
d(resourceId="com.android.mms:id/send_button").exists(timeout=10)
# 擷取按鈕的文本,逾時時間10秒
d(resourceId="com.android.mms:id/send_button").get_text(timeout=10)
# 輸入文本,此處需要元素是輸入框
d(text="請輸入内容").send_keys("測試")
上面是我們平時最常用的對元素的操作,分别是點選元素、判斷元素是否出現、擷取元素的文本内容及輸入文本内容。中間兩項對我們自動化測試斷言比較有用,比如有的用例是點選某元素後另外一個元素會出現,就可以用 exists(),如果是我們要對某個元素文本進行斷言,則可以使用 get_text()。最後是向輸入框輸入文本,比如我們需要執行搜尋操作,我們便可以定位到搜尋輸入框,然後使用 send_keys() 輸入搜尋關鍵字。需要注意如果元素不是輸入框會報錯。
通過XPath方式定位元素
有些元素既沒有 text,id 等屬性,無法直接定位到的時候我們可以使用 XPath 的方式定位元素。XPath 定位元素的方式是通過元素層級,從有 text,id 等屬性的元素一層一層去找到我們需要的元素,是以一般 XPath 定位元素的方式會比較慢一些。下面舉個例子:
聯系人添加群組
上面手機聯系人應用裡我們想要添加群組,發現“+”這個按鈕既沒有 text,也沒有 id,如果想唯一定位到該元素就要用 XPath 的方式了。看右側的 Hierarchy 發現該元素屬于 id為 com.android.contacts:id/titleBtnBar 的元素,那麼我們可以這樣定位到該元素
d.xpath("//*[@resource-id='com.android.contacts:id/titleBtnBar']/android.widget.LinearLayout[3]/android.widget.Button")
這裡主要介紹 uiautomator2 怎麼使用 XPath 定位,關于 XPath 表達式如何寫,可能需要很長的篇幅來寫,大家可以搜尋相關教程學習。
手機的其它操作
上面其實主要是操作應用的方法,uiautomator2 還有很多其它操作手機的方法,下面列舉一些
- 安裝應用
d.app_install(data) # data 可以是安裝包路徑,安裝包二進制資料或安裝包下載下傳連結
- 啟動應用
d.app_start("com.package_name") # 傳入要啟動的應用的包名
- 停止應用
d.app_stop("com.example") # 強行停止包名為 com.example 的應用
d.app_clear('com.example') # 清除包名為 com.example 的應用的應用資料
d.app_stop_all(excludes=['com.example']) # 強行停止所有正在運作的應用,除了包名為 com.example 的應用
- 截圖
d.screenshot("screenshot.png") # 對手機進行截圖并儲存在腳本所在目錄
img = d(resourceId="com.android.mms:id/send_button").screenshot()
img.save("send_button.jpg") # 對頁面上指定的元素截圖
- 推送檔案
# 向手機推送檔案
d.push("test.txt", "/sdcard/") # 推送檔案至手機 /sdcard/ 目錄下
d.push("test.txt", "/sdcard/file.txt") # 推送檔案至手機 /sdcard/ 目錄下并命名為 file.txt
# 從手機向電腦推送檔案
d.pull("/sdcard/file.txt", "test.txt") # 将檔案推送至電腦,如果手機上沒有此檔案則會報錯
寫在最後
此篇文章向大家介紹了 uiautomator2 的一些用法,下一篇文章會介紹 pytest 的一些基本使用方法,包括 fixture 方法、contest 檔案、pytest.ini 配置檔案的一些知識。