Android 自動化測試
Python +Android +uiautomator test 在init中定義的方法
uiautomator
該模塊是android的一個python包裝uiautomator測試框架。它適用於Android 4.1+,只需通過adb連接Android設備,無需在Android設備上安裝任何東西。
從 uiautomator 進口設備的 e
d.screen.on()
D(id= “時鐘”)。點擊()
安裝
$ pip install uiautomator
前提條件
- 安裝Android的SDK,並設置
ANDROID_HOME
環境以正確的路徑。 - 啟用設備上的ADB設置,並使用USB連接您的Android設備與您的電腦。
導入uiautomator
-
如果
ANDROID_SERIAL
在環境中定義的,或只有一個連接的設備:從 uiautomator 進口設備的 e
-
檢索設備對象時,限制序列號
從 uiautomator 進口設備 e =設備(‘ 014E05DE0F02000E “)
-
speficy在其他計算機上運行的adb服務器主機和端口
雖然亞行支持
-a
選項SDK 4.3以來,但現在它有一個bug。在所有接口而不是localhost上啟動adb服務器偵聽的唯一方法是adb -a -P 5037 fork-server server &
從 uiautomator 進口設備 e =設備(‘ 014E05DE0F02000E ‘,adb_server_host = “ 192.168.1.68 ”,adb_server_port = 5037)
註:在下面的例子中,我們使用d
代表Android設備對象。
目錄
基本API用法
- 關鍵事件設備的操作
- 手勢設備的交互
- 屏幕設備的操作
觀察者介紹
處理程序介紹
選擇器介紹
- 如何選擇Child和sibling UI對象
- 獲取特定的UI對象狀態及其信息
- 對選中的UI對象執行單擊操作
- 針對特定ui對象的手勢動作
基本API用法
此部分通過一些簡單的示例顯示設備的正常操作。
-
檢索設備信息
d.info
以下是可能的結果:
{ u‘displayRotation‘: 0, u‘displaySizeDpY‘: 640, u‘displaySizeDpX‘: 360, u‘currentPackageName‘: u‘com.android.launcher‘, u‘productName‘: u‘takju‘, u‘displayWidth‘: 720, u‘sdkInt‘: 18, u‘displayHeight‘: 1184, u‘naturalOrientation‘: True }
關鍵事件設備的操作
-
打開/關閉屏幕
#在屏幕上打開 d.screen.on() #關閉屏幕 d.screen.off()
替代方法是:
#喚醒設備 d.wakeup() #睡眠設備,一樣關閉屏幕。 d.sleep()
-
按硬/軟鍵
#按home鍵 d.press.home() #按返回鍵 d.press.back() #正常的方式按返回鍵 d.press( “回”) #按下鍵碼0×07(0)與元ALT (0X02)上 d.press( 0x的 07, 0X 02)
-
目前支持下列鍵:
home
back
left
right
up
down
center
menu
search
enter
delete
(或del
)recent
(最近的應用程式)volume_up
volume_down
volume_mute
camera
power
你可以找到所有關鍵代碼定義的Android的KeyEvent。
手勢設備的交互
-
單擊屏幕
#點擊(X,Y)在屏幕上 d.click(X,Y)
-
長按屏幕
#長按(X,Y)在屏幕上 d.long_click(X,Y)
-
滑動
#從(SX,SY)輕掃(EX,EY) d.swipe(SX,SY,EX,EY) #從(SX,SY)輕掃(EX,EY)與10個步驟 d.swipe(SX,SY ,前,安永,步驟= 10)
-
拖動
#從(SX,SY)拖動(EX,EY) d.drag(SX,SY,EX,EY) #從(SX,SY)拖動(EX,EY)與10個步驟 d.drag(SX,SY ,前,安永,步驟= 10)
屏幕設備的操作
-
檢索/設置方向
可能的方向是:
natural
要麽n
left
要麽l
right
要麽r
upsidedown
或u
(不能設定)
#檢索方向,也可能是“天然”或“左”或“右”或“upsidedown” 方向 = d.orientation #設置定向和凍結旋轉。 #指出:“upsidedown”不能設置到Android 4.3的。 d.orientation = “升” #或“左”的 d.orientation = “ - [R ” #或“右” d.orientation = “ ? ” #或“自然”
-
凍結/取消凍結旋轉
#凍結旋轉 d.freeze_rotation() #取消凍結旋轉 d.freeze_rotation(假)
-
截取屏幕截圖
#采取截圖並保存到本地文件“home.png”,直到Android 4.2或不能工作。 d.screenshot( “ home.png ”)
-
轉儲窗口層次結構
#轉儲widown層次結構並保存到本地文件“hierarchy.xml” d.dump( “ hierarchy.xml ”) #或獲得回報傾倒內容(Unicode)的。 XML = d.dump()
-
打開通知或快速設置
#開放的通知,不能工作,直到Android 4.3的。 d.open.notification() #開啟快速設定,不能工作,直到Android 4.3的。 d.open.quick_settings()
-
等待空閑或窗口更新
#等待當前窗口空閑 d.wait.idle() #等待,直到窗口更新事件發生 d.wait.update()
觀察者
你可以註冊守望者執行某些動作時,選擇器不能找到匹配。
-
註冊觀察者
當選擇器找不到匹配項時,uiautomator將運行所有註冊的觀察器。
- 條件匹配時點擊目標
d.watcher( “ AUTO_FC_WHEN_ANR ”)。當(文= “ ANR ”)。當(文= “等待”)\ 。點擊(文字= “強制關閉”) # d.watcher(名)##創建一個新的命名觀察者。 # 。當(條件)##觀察者的UiSelector條件。 # 。點擊(目標)##執行對目標UiSelector點擊動作。
- 條件匹配時按鍵
d.watcher( “ AUTO_FC_WHEN_ANR ”)。當(文= “ ANR ”)。當(文= “等待”)\ .press.back.home() #另類的方式來定義它,如下 d.watcher( “ AUTO_FC_WHEN_ANR ”)。當(文= “ ANR ”)。當(文= “等待”)\ 。按(“回”,“家”) # d.watcher(名)##創建一個新的名為守望。# 。當(條件)##觀察者的UiSelector條件。# 。按<鍵名> ...... <鍵名>。()##按下按鍵逐個順序。# Alternavie方式定義按鍵順序是按(<keybname>,...,<鍵名>)
-
檢查命名的監視器是否觸發
觸發觀察者,這意味著觀察者運行並且其所有條件都匹配。
d.watcher( “ watcher_name ”).triggered #真在指定守望的情況下觸發,否則為假
-
刪除命名監視器
#刪除觀察者 d.watcher( “ watcher_name ”)上卸下擺臂()
-
列出所有觀察者
d.watchers #所有註冊wachers‘名稱的列表
-
檢查是否有任何觀察者觸發
d.watchers.triggered # 真正的觸發任何看守的情況下,
-
重置所有觸發的觀察者
#重置所有觸發觀察家,在那之後,d.watchers.triggered會是假的。 d.watchers.reset()
-
Remvoe觀察者
#刪除所有已註冊的觀察家 d.watchers.remove() #刪除指定的守望者一樣,同樣d.watcher(“watcher_name”)。remove()方法 d.watchers.remove( “ watcher_name ”)
-
強制運行所有觀察者
#力量來運行所有註冊的觀察者 d.watchers.run()
處理程序
處理程序的功能與Watcher相同,只是它實現了我們的Android uiautomator。處理程序和觀察程序之間最不同的用法是,處理程序可以使用自定義的回調函數。
高清 fc_close(設備):
如果設備(文= ‘強制關閉“).exists:
設備(文= ‘強制關閉”)。點擊()
返回 真 #返回True手段打破處理程序回調函數的循環。
#在處理回調函數反過來
d.handlers.on(fc_close) #關閉句柄回調函數
d.handlers.off(fc_close)
選擇器
選擇器是標識當前窗口中的特定ui對象。
#要入圍對象,文字是“時鐘”和它的類名是“android.widget.TextView‘
D(文= ‘時鐘‘,的className = ‘ android.widget.TextView ‘)
選擇器支持以下參數。請參閱UiSelector DOC java的詳細信息。
text
,textContains
,textMatches
,textStartsWith
className
,classNameMatches
description
,descriptionContains
,descriptionMatches
,descriptionStartsWith
checkable
,checked
,clickable
,longClickable
scrollable
,enabled
,focusable
,focused
,selected
packageName
,packageNameMatches
resourceId
,resourceIdMatches
index
,instance
子對象和同級UI對象
-
兒童
#得到孩子或孫子 D(的className = “ android.widget.ListView ”).child(文= “藍牙”)
-
兄弟
#得到同胞的兄弟姐妹或子女 D(文= “谷歌”).sibling(的className = “ android.widget.ImageView ”)
-
子文本或描述或實例
#得到孩子匹配的className =“android.widget.LinearLayout” #而且它或它的子女或孫子包含文本“藍牙” D(的className = “ android.widget.ListView ”, RESOURCEID = “機器人:ID /列表”) .child_by_text( “藍牙”,的className = “ android.widget.LinearLayout ”)#允許滾動搜索,獲得子 D(的className = “ android.widget.ListView ”, RESOURCEID = “機器人:ID /列表”)。 child_by_text( “藍牙”, allow_scroll_search = 真, 的className = “ android.widget.LinearLayout ” )
-
child_by_description
是找到子哪個或哪些是孫子包含指定的描述中,其他是相同的child_by_text
。 -
child_by_instance
是在其子層次結構中指定實例的任何位置找到具有子UI元素的子項。這是一個沒有可見的意見進行滾動。
詳情請參閱以下鏈接:
- UiScrollable,
getChildByDescription
,getChildByText
,getChildByInstance
- UiCollection,
getChildByDescription
,getChildByText
,getChildByInstance
上面的方法支持鏈接調用,例如對於下層
< 節點 指數 = “ 0 ” 文本 = “ ” 資源ID = “機器人:ID /列表” 級 = “ android.widget.ListView ” ...> < 節點 指數 = “ 0 ” 文本 = “ WIRELESS & NETWORKS ” 資源-id = “ ” 類 = “ android.widget.TextView ” ... /> < 節點 索引 = “ 1 ” 文本 = “ ” 資源ID = “ ” 類 = “ android.widget.LinearLayout ” ...> < 節點 指數 = “ 1 ” 文本 = “ ” 資源ID = “ ” 級 = “ android.widget.RelativeLayout ” ...> < 節點 指數 = “ 0 ” 文本 = “無線網絡連接” 資源ID = “機器人: ID /標題“ 級 = ” android.widget.TextView “ ... /> </ 節點 > < 節點 指數 = ” 2 “ 文本 = ” ON “ 資源ID = ” com.android.settings:ID / switchWidget “ 類 = “ android.widget.Switch ” ... /> </ 節點 > ... </ 節點 >
我們要點擊文本“Wi-Fi”右側的開關打開/打開Wi-Fi。因為有幾個開關,幾乎相同的屬性,所以我們不能使用類似
d(className="android.widget.Switch")
選擇的UI對象。相反,我們可以使用下面的代碼來選擇它。D(的className = “ android.widget.ListView ”,RESOURCEID = “機器人:ID /列表”)\ .child_by_text( “無線網絡連接”,的className = “ android.widget.LinearLayout ”)\ .child(的className = “機器人.widget.Switch “)\ 。點擊()
-
-
相對位置
此外,我們可以用相對位置的方法來獲取視圖:
left
,right
,top
,bottom
。d(A).left(B)
,意味著在左側選擇B。d(A).right(B)
,表示選擇A右側的B.d(A).up(B)
,表示選擇B以上的A.d(A).down(B)
,表示在A下選擇B.
所以對於上面的情況,我們可以寫代碼:
##選擇的“無線網絡連接”右側的“開關” D(文= “無線網絡連接”).right(的className = “ android.widget.Switch ”)。點擊()
-
多個實例
有時,屏幕可能包含多個視圖與相同的例如文本,那麽你將不得不使用選擇器中的“實例”屬性,如下所示:
D(文= “新增”,比如= 0) #這意味著一審文本“新增”
但是,uiautomator提供了類似的方法來使用它。
#得到的文本意見的計當前屏幕上的“添加新的” D(文= “新增”).Count之間#一樣count屬性LEN(D(文= “新增”)) #通過索引獲取實例 e (文= “新增”)[ 0 ] D(文= “新增”)[ 1 ] ... #叠代器的視圖中 D(文= “添加新”): view.info # ...
註意:當您使用選擇喜歡的列表,你必須確保屏幕保持不變,否則你可能會得到UI未找到錯誤。
獲取所選的ui對象狀態及其信息
-
檢查特定ui對象是否存在
D(文= “設置”).exists #是否存在真,否則假 d.exists(文= “設置”)#以上財產的別名。
-
檢索特定ui對象的信息
D(文= “設置”).INFO
以下是可能的結果:
{ u‘contentDescription‘: u‘‘, u‘checked‘: False, u‘scrollable‘: False, u‘text‘: u‘Settings‘, u‘packageName‘: u‘com.android.launcher‘, u‘selected‘: False, u‘enabled‘: True, u‘bounds‘: {u‘top‘: 385, u‘right‘: 360, u‘bottom‘: 585, u‘left‘: 200}, u‘className‘: u‘android.widget.TextView‘, u‘focused‘: False, u‘focusable‘: True, u‘clickable‘: True, u‘chileCount‘: 0, u‘longClickable‘: True, u‘visibleBounds‘: {u‘top‘: 385, u‘right‘: 360, u‘bottom‘: 585, u‘left‘: 200}, u‘checkable‘: False }
-
設置/清除可編輯字段的文本
D(文= “設置”).clear_text() #清除文字 D(文= “設置”).set_text( “我的文字...... ”) #設置文本
對選中的ui對象執行單擊操作
-
點擊特定的ui對象
#點擊特定的UI對象的中心 D(文= “設置”)。單擊() #點擊具體的UI對象的bottomright角落 D(文= “設置”)).click.bottomright( #請點擊具體的UI對象的左上邊角 D(文= “設置”).click.topleft() #點擊等到新窗口更新 D(文= “設置”).click.wait()
-
長時間點擊特定的ui對象
#長按一下特定的UI對象的中心 D(文= “設置”).long_click() #長按具體的UI對象的bottomright角落 D(文= “設置”).long_click.bottomright() #長按具體的UI對象的左上邊角 D(文= “設置”).long_click.topleft()
針對特定ui對象的手勢動作
-
將ui對象拖動到另一個點或ui對象
#註:拖不能設置到Android 4.3的。 #拖拽的UI對象,以點(X,Y) D(文= “設置”).drag.to(X,Y,步驟= 100) #拖拽的UI對象到另一個UI對象(中心), D(文= “設置“).drag.to(文= ”時鐘“,步驟= 50)
-
從ui對象的中央滑動到其邊緣
滑動支持4個方向:
left
right
top
bottom
D(文= “設置”).swipe.right() D(文= “設置”).swipe.left(步驟= 10), D(文= “設置”).swipe.up(步驟= 10), D(文字= “設置”).swipe.down()
-
兩點手勢從一個點到另一個點
D(文= “設置”).gesture((SX1,SY1),(SX2,SY2))\ 。要((EX1,EY1),(EX2,EY2))
-
在特定ui對象的兩點姿態
支持兩種手勢:
In
,從邊到中心Out
,從中心到邊緣
#註:捏不能設置到Android 4.3的。 #從邊緣到中心。這裏是“在”不“,在” D(文= “設置”).pinch.In(百分比= 100,步= 10) #從中心到邊緣 D(文= “設置”).pinch.Out()
-
等待特定ui對象出現或消失
#等到UI對象出現 D(文= “設置”).wait.exists(超時= 3000) #等待,直到UI對象轉眼 D(文= “設置”).wait.gone(超時= 1000)
-
對特定的ui對象執行fling(可滾動)
可能的屬性:
horiz
要麽vert
forward
或backward
或toBeginning
或toEnd
#一扔前進(默認)垂直(默認) D(滾動= 真).fling() #一扔前進horizentally D(滾動= 真).fling.horiz.forward() #一扔向後垂直 D(滾動= 真).fling .vert.backward() #一扔到horizentally開始 D(滾動= 真).fling.horiz.toBeginning( max_swipes = 1000) #來結束垂直一扔 D(滾動= 真).fling.toEnd()
-
在特定的ui對象上滾動(可滾動)
可能的屬性:
horiz
要麽vert
forward
或backward
或toBeginning
或toEnd
或to
#向前滾動(默認)垂直(默認) D(滾動= 真).scroll(步驟= 10) #向前滾動horizentally D(滾動= 真).scroll.horiz.forward(步驟= 100) #向後滾動垂直 D(滾動= 真).scroll.vert.backward() #滾動到horizentally開始 D(滾動= 真).scroll.horiz.toBeginning(步驟= 100, max_swipes = 1000) #滾動到年底垂直 D(滾動= 真)。 scroll.toEnd() #向前滾動,直到垂直特定的UI對象出現 D(滾動= 真).scroll.to(文= “安全性”)
貢獻
- 分叉repo,並克隆到您的計算機。
- 從檢出一個新分支
develop
的分支 - 安裝要求:
pip install -r requirements.txt
- 進行更改,然後更新測試。不要忘記在“提供者”部分的末尾添加您的姓名
- 通過所有的測試和代碼必須包括:
tox
。 - 提交你的修改,並提交拉請求
develop
分支。
貢獻者
- 小蔥他(@xiaocong)
- 鄒圓圓(@yuanyuan)
問題和討論
如果您有任何錯誤報告或煩惱請報告給我們的問題跟蹤GitHub的問題。
如果你有你想討論任何建議,新的功能要求或話題,請提交您的主題ostio。
筆記
- Android的uiautomator適用於Android 4.1及以上版本,所以在使用它之前,請確保你的設備是Android4.1 +。
- 有些方法僅工作在Android 4.2 / 4.3,所以你最好閱讀詳細uiautomator的Java文檔在使用它之前。
- 該模塊采用uiautomator-jsonrpc服務器作為後臺程序與設備進行通信。
- 該模塊僅在python2.7 / 3.2 / 3.3 / pypy上測試。
常問問題
-
無法啟動JSONRPC服務器:
raise IOError("RPC server not started!")
它可能是由網絡,設備或環境引起的。因此,當您遇到此問題,請按照以下步驟,嘗試手動啟動JSONRPC服務器。
-
從下載jar文件uiautomator jsonrpc服務器。
-
Adb將下載的jar文件推送到
/data/local/tmp/
-
通過命令啟動jsonrpc服務器:
adb shell uiautomator runtest bundle.jar uiautomator-stub.jar -c com.github.uiautomatorstub.Stub
-
Adb將本地端口轉發到設備端口:
adb forward tcp:9008 tcp:9008
-
檢查jsonrpc服務器是否正常:
curl -d ‘{"jsonrpc":"2.0","method":"deviceInfo","id":1}‘ localhost:9008/jsonrpc/0
如果你看到類似的消息
{"jsonrpc":"2.0","id":1,"result":{"currentPackageName":"android","displayHeight":1280,"displayRotation":0,"displaySizeDpX":0,"displaySizeDpY":0,"displayWidth":720,"productName":"falcon","sdkInt":17,"naturalOrientation":true}}
,則表示服務器已啟動。
如果你可以手動啟動jsonrpc服務器,但你的腳本總是滿足
IOError("RPC server not started!")
,請提交問題github上的問題。 -
-
錯誤
httplib.BadStatusLine: ‘‘
JsonRPC服務器需要訪問設備上的臨時目錄,但在一些低層設備上,它可能會遇到錯誤,在訪問臨時文件沒有連接SD卡。因此,如果您遇到錯誤,請插入SD卡,然後重試。
Android 自動化測試