1. 程式人生 > >Android 自動化測試

Android 自動化測試

unicode lac 回調 工作 info 部分 字段 結束 itl

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
    • upsidedownu(不能設定)
    #檢索方向,也可能是“天然”或“左”或“右”或“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的詳細信息。

  • texttextContainstextMatchestextStartsWith
  • classNameclassNameMatches
  • descriptiondescriptionContainsdescriptionMatchesdescriptionStartsWith
  • checkablecheckedclickablelongClickable
  • scrollableenabledfocusablefocusedselected
  • packageNamepackageNameMatches
  • resourceIdresourceIdMatches
  • indexinstance

子對象和同級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,getChildByDescriptiongetChildByTextgetChildByInstance
    • UiCollection,getChildByDescriptiongetChildByTextgetChildByInstance

    上面的方法支持鏈接調用,例如對於下層

    < 節點 指數 = “ 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 “)\ 
      。點擊()
  • 相對位置

    此外,我們可以用相對位置的方法來獲取視圖:leftrighttopbottom

    • 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
    • forwardbackwardtoBeginningtoEnd
    #一扔前進(默認)垂直(默認) 
    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
    • forwardbackwardtoBeginningtoEndto
    #向前滾動(默認)垂直(默認) 
    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服務器。

    1. 從下載jar文件uiautomator jsonrpc服務器。

    2. Adb將下載的jar文件推送到 /data/local/tmp/

    3. 通過命令啟動jsonrpc服務器:

      adb shell uiautomator runtest bundle.jar uiautomator-stub.jar -c com.github.uiautomatorstub.Stub
      
    4. Adb將本地端口轉發到設備端口:

      adb forward tcp:9008 tcp:9008
      
    5. 檢查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 自動化測試