乾貨 | 一文搞定 uiautomator2 自動化測試工具使用

2021-02-14 霍格沃茲測試學院

霍格沃茲測試學院是 python-uiautomator2 金牌贊助商,跟著開源項目作者學測試開發實戰,文末加群。

一、背景簡介

Google 官方提供了一個 Android 自動化測試工具(Java 庫),基於 Accessibility 服務,功能很強,可以對第三方 App 進行測試,獲取屏幕上任意一個 App 的任意一個控制項屬性,並對其進行任意操作,但有兩個缺點:

測試腳本只能使用 Java 語言;

測試腳本要打包成 jar 或者 apk 包上傳到設備上才能運行;

實際工作中,我們希望測試邏輯能夠用 Python 編寫,能夠在電腦上運行的時候就控制手機。所以基於這個目的開發了 python-uiautomator2 自動化測試開源工具,其封裝了谷歌自帶的 uiautomator2 測試框架,可以運行在支持 Python 的任一系統上,目前版本為 V2.10.2。

GitHub 開源地址:

https://github.com/openatx/uiautomator2

二、工作原理

如圖所示,python-uiautomator2 主要分為兩個部分,python 客戶端,行動裝置

整個過程:

在行動裝置上安裝 atx-agent(守護進程),隨後 atx-agent 啟動 uiautomator2 服務(默認 7912 埠)進行監聽;

在 PC 上編寫測試腳本並執行(相當於發送 HTTP 請求到行動裝置的 server 端);

行動裝置通過 WIFI 或 USB 接收到 PC 上發來的 HTTP 請求,執行制定的操作;

三、安裝與啟動3.1 安裝 uiautomator2

使用 pip 安裝

pip install -U uiautomator2

安裝完成後,使用如下 python 代碼查看環境是事配置成功

說明:後文中所有代碼都需要導入 uiautomator2 庫,為了簡化我使用 u2 代替,d 代表 driver

import uiautomator2 as u2
# 連接並啟動
d = u2.connect() 
print(d.info)

能正確列印出設備的信息則表示安裝成功

注意:需要安裝 adb 工具,並配置到系統環境變量,才能操作手機。

安裝有問題可以到 issue 列表查詢:

https://github.com/openatx/uiautomator2/wiki/Common-issues

3.2 安裝 weditor

weditor 是一款基於瀏覽器的 UI 查看器,用來幫助我們查看 UI 元素定位。

因為 uiautomator 是獨佔資源,所以當 atx 運行的時候 uiautomatorviewer 是不能用的,為了減少 atx 頻繁的啟停,就需要用到此工具

使用 pip 安裝

pip install -U weditor

查看安裝是否成功

weditor --help

出現如下信息表示安裝成功

運行 weditor

python -m weditor
#或者直接在命令行運行
weditor

四、元素定位4.1 使用方法

d(定位方式 = 定位值)
#例:
element = d(text='Phone')
#這裡返回的是一個列表,當沒找到元素時,不會報錯,只會返回一個長度為 0 的列表
#當找到多個元素時,會返回多個元素的列表,需要加下標再定位
element[0].click()
#獲取元素個數
print(element.count)

4.2 支持的定位方式

ui2 支持 android 中 UiSelector 類中的所有定位方式,詳細可以在這個網址查看 https://developer.android.com/reference/android/support/test/uiautomator/UiSelector

整體內容如下 , 所有的屬性可以通過 weditor 查看到

名稱描述texttext 是指定文本的元素textContainstext 中包含有指定文本的元素textMatchestext 符合指定正則的元素textStartsWithtext 以指定文本開頭的元素classNameclassName 是指定類名的元素classNameMatchesclassName 類名符合指定正則的元素descriptiondescription 是指定文本的元素descriptionContainsdescription 中包含有指定文本的元素descriptionMatchesdescription 符合指定正則的元素descriptionStartsWithdescription 以指定文本開頭的元素checkable可檢查的元素,參數為 True,Falsechecked已選中的元素,通常用於複選框,參數為 True,Falseclickable可點擊的元素,參數為 True,FalselongClickable可長按的元素,參數為 True,Falsescrollable可滾動的元素,參數為 True,Falseenabled已激活的元素,參數為 True,Falsefocusable可聚焦的元素,參數為 True,Falsefocused獲得了焦點的元素,參數為 True,Falseselected當前選中的元素,參數為 True,FalsepackageNamepackageName 為指定包名的元素packageNameMatchespackageName 為符合正則的元素resourceIdresourceId 為指定內容的元素resourceIdMatchesresourceId 為符合指定正則的元素4.3 子元素和兄弟定位

子元素定位

child()

#查找類名為 android.widget.ListView 下的 Bluetooth 元素
d(className="android.widget.ListView").child(text="Bluetooth")
# 下面這兩種方式定位有點不準確,不建議使用
d(className="android.widget.ListView")\
.child_by_text("Bluetooth",allow_scroll_search=True)
d(className="android.widget.ListView").child_by_description("Bluetooth")

兄弟元素定位

sibling()

#查找與 google 同一級別,類名為 android.widget.ImageView 的元素
d(text="Google").sibling(className="android.widget.ImageView")

鏈式調用

d(className="android.widget.ListView", resourceId="android:id/list") \
  .child_by_text("Wi‑Fi", className="android.widget.LinearLayout") \
  .child(className="android.widget.Switch") \
  .click()

4.4 相對定位

相對定位支持在left, right, top, bottom, 即在某個元素的前後左右

d(A).left(B),# 選擇 A 左邊的 B
d(A).right(B),# 選擇 A 右邊的 B
d(A).up(B), #選擇 A 上邊的 B
d(A).down(B),# 選擇 A 下邊的 B
#選擇 WIFI 右邊的開關按鈕
d(text='Wi‑Fi').right(resourceId='android:id/widget_frame')

4.5 元素常用 API

表格標註有 @property 裝飾的類屬性方法,均為下方示例方式

d(test="Settings").exists

方法

描述返回值備註exists()判斷元素是否存在True,Flase@propertyinfo()返回元素的所有信息字典@propertyget_text()返回元素文本字符串
set_text(text)設置元素文本None
clear_text()清空元素文本None
center()返回元素的中心點位置(x,y)基於整個屏幕的點

exists 其它使用方法:

d.exists(text='Wi‑Fi',timeout=5)

info() 輸出信息:

{
  "bounds": {
    "bottom": 407,
    "left": 216,
    "right": 323,
    "top": 342
  },
  "childCount": 0,
  "className": "android.widget.TextView",
  "contentDescription": null,
  "packageName": "com.android.settings",
  "resourceName": "android:id/title",
  "text": "Wi‑Fi",
  "visibleBounds": {
    "bottom": 407,
    "left": 216,
    "right": 323,
    "top": 342
  },
  "checkable": false,
  "checked": false,
  "clickable": false,
  "enabled": true,
  "focusable": false,
  "focused": false,
  "longClickable": false,
  "scrollable": false,
  "selected": false
}

可以通過上方信息分別獲取元素的所有屬性

4.6 XPATH 定位

因為 Java uiautoamtor 中默認是不支持 xpath,這是屬於 ui2 的擴展功能,速度會相比其它定位方式慢一些

在 xpath 定位中,ui2 中的 description 定位需要替換為 content-desc,resourceId 需要替換為 resource-id

使用方法

# 只會返回一個元素,如果找不到元素,則會報 XPathElementNotFoundError 錯誤
# 如果找到多個元素,默認會返回第 0 個
d.xpath('//*[@resource-id="com.android.launcher3:id/icon"]')

# 如果返回的元素有多個,需要使用 all() 方法返回列表
# 使用 all 方法,當未找到元素時,不會報錯,會返回一個空列表
d.xpath('//*[@resource-id="com.android.launcher3:id/icon"]').all()

五、設備交互5.1 單擊

d(text='Settings').click()
#單擊直到元素消失 , 超時時間 10,點擊間隔 1
d(text='Settings').click_gone(maxretry=10, interval=1.0)

5.2 長按

d(text='Settings').long_click()

5.3 拖動

Android<4.3 時不能使用拖動

# 在 0.25S 內將 Setting 拖動至 Clock 上,拖動元素的中心位置
# duration 默認為 0.5, 實際拖動的時間會比設置的要高
d(text="Settings").drag_to(text="Clock", duration=0.25)

# 拖動 settings 到屏幕的某個點上
d(text="Settings").drag_to(877,733, duration=0.25)

#兩個點之間的拖動 , 從點 1 拖動至點 2
d.drag(x1,y1,x2,y2)

5.4 滑動

滑動有兩個,一個是在 driver 上操作,一個是在元素上操作

元素上操作

從元素的中心向元素邊緣滑動

# 在 Setings 上向上滑動。steps 默認為 10
# 1 步約為 5 毫秒,因此 20 步約為 0.1 s
d(text="Settings").swipe("up", steps=20) 

driver 上操作

即對整個屏幕操作

# 實現下滑操作
x,y = d.window_size()
x1 = x / 2
y1 = y * 0.1
y2 = y * 0.9
d.swipe(x1,y1,x1,y2)

driver 滑動的擴展方法,可以直接實現滑動,不需要再自己封裝定位點

# 支持前後左右的滑動
# "left", "right", "up", "down"
# 下滑操作
d.swipe_ext("down")

5.5 雙指操作

android>4.3

對元素操作

d(text='Settings').gesture(start1,start2,end1,end2,)
# 放大操作
d(text='Settings').gesture((525,960),(613,1121),(135,622),(882,1540))

封裝好的放大縮小操作

# 縮小
d(text="Settings").pinch_in()
# 放大
d(text="Settings").pinch_out()

5.6 等待元素出現或者消失

# 等待元素出現
d(text="Settings").wait(timeout=3.0)
# 等待元素消失,返回 True False,timout 默認為全局設置的等待時間
d(text='Settings').wait_gone(timeout=20)

5.7 滾動界面

設置 scrollable 屬性為 True;

滾動類型:horiz 為水平,vert 為垂直;

滾動方向:

forward 向前

backward 向後

toBeginning 滾動至開始

toEnd 滾動至最後

to 滾動直接某個元素出現

所有方法均返回 Bool 值;

# 垂直滾動到頁面頂部 / 橫向滾動到最左側
d(scrollable=True).scroll.toBeginning()
d(scrollable=True).scroll.horiz.toBeginning()
# 垂直滾動到頁面最底部 / 橫向滾動到最右側
d(scrollable=True).scroll.toEnd()
d(scrollable=True).scroll.horiz.toEnd()
# 垂直向後滾動到指定位置 / 橫向向右滾動到指定位置
d(scrollable=True).scroll.to(description=" 指定位置 ")
d(scrollable=True).scroll.horiz.to(description=" 指定位置 ")
# 垂直向前滾動(橫向同理)
d(scrollable=True).scroll.forward()
# 垂直向前滾動到指定位置(橫向同理)
d(scrollable=True).scroll.forward.to(description=" 指定位置 ")
# 滾動直到 System 元素出現
d(scrollable=True).scroll.to(text="System")

Take screenshot of widget

im = d(text="Settings").screenshot()
im.save("settings.jpg")

5.8 輸入

5.8.1 輸入自定義文本

# 使用 adb 廣播的方式輸入
d.send_keys('hello')
# 清空輸入框
d.clear_text()

5.8.2 輸入按鍵

兩種方法

# 發送回車
d.press('enter')
# 第二種
d.keyevent('enter')

目前 press 支持的按鍵如下

  """
        press key via name or key code. Supported key name includes:
            home, back, left, right, up, down, center, menu, search, enter,
            delete(or del), recent(recent apps), volume_up, volume_down,
            volume_mute, camera, power.
        """

keyevent 是通過 「adb shell input keyevent」 方式輸入,支持按鍵更加豐富

更多詳細的按鍵信息 https://developer.android.com/reference/android/view/KeyEvent.html

5.8.3 輸入法切換

# 切換成 ui2 的輸入法,這裡會隱藏掉系統原本的輸入法 , 默認是使用系統輸入法
# 當傳入 False 時會使用系統默認輸入法,默認為 Fasle
d.set_fastinput_ime(True)
# 查看當前輸入法
d.current_ime()
#返回值
('com.github.uiautomator/.FastInputIME', True)

5.8.4 模擬輸入法功能

可以模擬的功能有 go ,search ,send ,next, done ,previous。

如果使用 press 輸入按鍵無效,可以嘗試使用此方法輸入

# 搜索功能
d.send_action("search")

5.9 toast 操作

# 獲取 toast, 當沒有找到 toast 消息時,返回 default 內容
d.toast.get_message(timout=5,default='no toast')
# 清空 toast 緩存
d.toast.reset()

5.10 監控界面

使用 wather 進行界面的監控,可以用來實現跳過測試過程中的彈框

當啟動 wather 時,會新建一個線程進行監控

可以添加多個 watcher

用法

# 註冊監控 , 當界面內出現有 allow 字樣時,點擊 allow
d.watcher.when('allow').click()

# 移除 allow 的監控
d.watcher.remove("allow")

# 移除所有的監控
d.watcher.remove()

# 開始後臺監控
d.watcher.start()
d.watcher.start(2.0) # 默認監控間隔 2.0s

# 強制運行所有監控
d.watcher.run()

# 停止監控
d.watcher.stop()

# 停止並移除所有的監控,常用於初始化
d.watcher.reset()

2.11.0 版本 新增了一個 watch_context 方法 , 寫法相比 watcher 更簡潔,官方推薦使用此方法來實現監控,目前只支持 click() 這一種方法。

wct = d.watch_context()
# 監控 ALLOW
wct.when("ALLOW").click()
# 監控 OK
wct.when('OK').click()
 # 開啟彈窗監控,並等待界面穩定(兩個彈窗檢查周期內沒有彈窗代表穩定)
wct.wait_stable()

#其它實現代碼
# 停止監控
wct.stop()

5.11 多點滑動

這裡可以用來實現圖案解鎖

使用 touch 類

# 模擬按下不放手
touch.down(x,y)
# 停住 3S
touch.sleep(x,y)
# 模擬移動
touch.move(x,y)
# 模擬放開
touch.up(x,y)
#實現長按 , 同一個點按下休眠 5S 後抬起
d.touch.down(252,1151).sleep(5).up(252,1151)
# 實現四點的圖案解鎖,目前只支持坐標點
d.touch.down(252,1151).move(559,1431).move(804,1674).move(558,1666).up(558,1666)

六、圖像操作6.1 截圖

d.screenshot('test.png')

6.2 錄製視頻

這個感覺是比較有用的一個功能,可以在測試用例開始時錄製,結束時停止錄製,然後如果測試 fail。則上傳到測試報告,完美復原操作現場,具體原理後面再去研究。

首先需要下載依賴,官方推薦使用鏡像下載:

pip3 install -U "uiautomator2[image]" -i https://pypi.doubanio.com/simple

執行錄製:

# 啟動錄製,默認幀率為 20
d.screenrecord('test.mp4')
# 其它操作
time.sleep(10)
#停止錄製,只有停止錄製了才能看到視頻 
d.screenrecord.stop()

6.3 圖片識別點擊

下載與錄製視頻同一套依賴。

這個功能是首先手動截取需要點擊目標的圖片,然後 ui2 在界面中去匹配這個圖片,目前我嘗試了精確試不是很高,誤點率非常高,不建議使用。

# 點擊 
d.image.click('test.png')
# 匹配圖片,返回相似度和坐標
# {'similarity': 0.9314796328544617, 'point': [99, 630]}
d.image.match('test.png')

七、應用管理7.1 獲取當前界面的 APP 信息

d.app_current()
#返回當前界面的包名,activity 及 pid
{
    "package": "com.xueqiu.android",
    "activity": ".common.MainActivity",
    "pid": 23007
}

7.2 安裝應用

可以從本地路徑及 url 下載安裝 APP,此方法無返回值,當安裝失敗時,會拋出 RuntimeError 異常

# 本地路徑安裝 
d.app_install('test.apk')
# url 安裝 
d.app_install('http://s.toutiao.com/UsMYE/')

7.3 運行應用

默認當應用在運行狀態執行 start 時不會關閉應用,而是繼續保持當前界面。

如果需要消除前面的啟動狀態,則需要加 stop=True 參數。

# 通過包名啟動
d.app_start("com.xueqiu.android",stop=True)

#源碼說明
    def app_start(self, package_name: str, 
                  activity: Optional[str]=None, 
                  wait: bool = False, 
                  stop: bool=False, 
                  use_monkey: bool=False):
        """ Launch application
        Args:
            package_name (str): package name
            activity (str): app activity
            stop (bool): Stop app before starting the activity. (require activity)
            use_monkey (bool): use monkey command to start app when activity is not given
            wait (bool): wait until app started. default False
        """

7.4 停止應用

stop 和 clear 的區別是結束應用使用的命令不同

stop 使用的是 「am force-stop」

clear 使用的是 「pm clear」

# 通過包名結束單個應用
d.app_stop("com.xueqiu.android")
d.app_clear('com.xueqiu.android')

# 結束所有應用 , 除了 excludes 參數列表中的應用包名
# 如果不傳參,則會只保留兩個依賴服務應用
# 會返回一個結束應用的包名列表
d.app_stop_all(excludes=['com.xueqiu.android'])

7.5 獲取應用信息

d.app_info('com.xueqiu.android')

#輸出
{
    "packageName": "com.xueqiu.android",
    "mainActivity": "com.xueqiu.android.common.splash.SplashActivity",
    "label": " 雪球 ",
    "versionName": "12.6.1",
    "versionCode": 257,
    "size": 72597243
}

7.6 獲取應用圖標

img = d.app_icon('com.xueqiu.android')
img.save('icon.png')

7.7 等待應用啟動

# 等待此應用變為當前應用,返回 pid,超時未啟動成功則返回 0
# front 為 true 表示等待 app 成為當前 app,
# 默認為 false,表示只要後臺有這個應用的進程就會返回 PID
d.app_wait('com.xueqiu.android',60,front=True)

7.8 卸載應用

# 卸載成功返回 true, 沒有此包或者卸載失敗返回 False
d.app_uninstall('com.xueqiu.android')

# 卸載所有自己安裝的第三方應用 , 返回卸載 app 的包名列表
# excludes 表示不卸載的列表
# verbose 為 true 則會列印卸載信息
d.app_uninstall_all(excludes=[],verbose=True)

卸載全部應用返回的包名列表並一定是卸載成功了,最好使用 verbose=true 列印一下信息,這樣可以查看到是否卸載成功

uninstalling com.xueqiu.android  OK
uninstalling com.android.cts.verifier  FAIL

或者可以修改一下源碼,使其只輸出成功的包名,注釋的為增加的代碼,未注釋的是源碼

    def app_uninstall_all(self, excludes=[], verbose=False):
        """ Uninstall all apps """
        our_apps = ['com.github.uiautomator', 'com.github.uiautomator.test']
        output, _ = self.shell(['pm', 'list', 'packages', '-3'])
        pkgs = re.findall(r'package:([^\s]+)', output)
        pkgs = set(pkgs).difference(our_apps + excludes)
        pkgs = list(pkgs)
        # 增加一個卸載成功的列表
        #sucess_list = []
        for pkg_name in pkgs:
            if verbose:
                print("uninstalling", pkg_name, " ", end="", flush=True)
            ok = self.app_uninstall(pkg_name)
            if verbose:
                print("OK" if ok else "FAIL")
                # 增加如下語句,當成功則將包名加入 list
                #if ok:
                 #   sucess_list.append(pkg_name)
     # 返回成功的列表
    #    return sucess_list
        return pkgs

八、其它實用方法8.1 連接設備

#當 PC 只連接了一個設備時,可以使用此種方式
d = u2.connect()
#返回的是 Device 類 , 此類繼承方式如下

class Device(_Device, _AppMixIn, _PluginMixIn, _InputMethodMixIn, _DeprecatedMixIn):
    """ Device object """


# for compatible with old code
Session = Device

connect() 可以使用如下其它方式進行連接

#當 PC 與設備在同一網段時,可以使用 IP 地址和埠號通過 WIFI 連接,無需連接 USB 線
connect("10.0.0.1:7912")
connect("10.0.0.1") # use default 7912 port
connect("http://10.0.0.1")
connect("http://10.0.0.1:7912")
#多個設備時,使用設備號指定哪一個設備
connect("cff1123ea")  # adb device serial number

8.2 獲取設備及 driver 信息

8.2.1 獲取 driver 信息

d.info
#輸出
{
    "currentPackageName": "com.android.systemui",
    "displayHeight": 2097,
    "displayRotation": 0,
    "displaySizeDpX": 360,
    "displaySizeDpY": 780,
    "displayWidth": 1080,
    "productName": "freedom_turbo_XL",
    "screenOn": true,
    "sdkInt": 29,
    "naturalOrientation": true
}

8.2.2 獲取設備信息

會輸出測試設備的所有信息,包括電池,CPU,內存等

d.device_info
#輸出
{
    "udid": "61c90e6a-ba:1b:ba:46:91:0e-freedom_turbo_XL",
    "version": "10",
    "serial": "61c90e6a",
    "brand": "Schok",
    "model": "freedom turbo XL",
    "hwaddr": "ba:1b:ba:46:91:0e",
    "port": 7912,
    "sdk": 29,
    "agentVersion": "0.9.4",
    "display": {
        "width": 1080,
        "height": 2340
    },
    "battery": {
        "acPowered": false,
        "usbPowered": true,
        "wirelessPowered": false,
        "status": 2,
        "health": 2,
        "present": true,
        "level": 98,
        "scale": 100,
        "voltage": 4400,
        "temperature": 292,
        "technology": "Li-ion"
    },
    "memory": {
        "total": 5795832,
        "around": "6 GB"
    },
    "cpu": {
        "cores": 8,
        "hardware": "Qualcomm Technologies, Inc SDM665"
    },
    "arch": "",
    "owner": null,
    "presenceChangedAt": "0001-01-01T00:00:00Z",
    "usingBeganAt": "0001-01-01T00:00:00Z",
    "product": null,
    "provider": null
}

8.2.3 獲取屏幕解析度

# 返回(寬,高)元組
d.window_size()
# 例 解析度為 1080*1920
# 手機豎屏狀態返回 (1080,1920)
# 橫屏狀態返回 (1920,1080)

8.2.4 獲取 IP 地址

# 返回 ip 地址字符串,如果沒有則返回 None
d.wlan_ip

8.3 driver 全局設置

8.3.1 使用 settings 設置

查看 settings 默認設置

d.settings
#輸出

{
    #點擊後的延遲,(0,3)表示元素點擊前等待 0 秒,點擊後等待 3S 再執行後續操作
    'operation_delay': (0, 3),
    # opretion_delay 生效的方法,默認為 click 和 swipe
    # 可以增加 press,send_keys,long_click 等方式
    'operation_delay_methods': ['click', 'swipe'],
    # 默認等待時間,相當於 appium 的隱式等待
    'wait_timeout': 20.0,
    # xpath 日誌
    'xpath_debug': False
}

修改默認設置,只需要修改 settings 字典即可

#修改延遲為操作前延遲 2S 操作後延遲 4.5S
d.settings['operation_delay'] = (2,4.5)
#修改延遲生效方法
d.settings['operation_delay_methods'] = {'click','press','send_keys'}
# 修改默認等待
d.settings['wait_timeout'] = 10

8.3.2 使用方法或者屬性設置

# 默認值 60s, 
d.HTTP_TIMEOUT = 60 

# 僅當 TMQ=true 時有效,支持通過環境變量 WAIT_FOR_DEVICE_TIMEOUT 設置
d.WAIT_FOR_DEVICE_TIMEOUT = 70 

# 打不到元素時,等待 10 後再報異常
d.implicitly_wait(10.0)

d.debug = True
d.info
#輸出
15:52:04.736 $ curl -X POST -d '{"jsonrpc": "2.0", "id": "0eed6e063989e5844feba578399e6ff8", "method": "deviceInfo", "params": {}}' 'http://localhost:51046/jsonrpc/0'
15:52:04.816 Response (79 ms) >>>
{"jsonrpc":"2.0","id":"0eed6e063989e5844feba578399e6ff8","result":{"currentPackageName":"com.android.systemui","displayHeight":2097,"displayRotation":0,"displaySizeDpX":360,"displaySizeDpY":780,"displayWidth":1080,"productName":"freedom_turbo_XL","screenOn":true,"sdkInt":29,"naturalOrientation":true}}
<<< END

# 相當於 time.sleep(10)
d.sleep(10)

8.4 亮滅屏

# 亮屏
d.screen_on()
# 滅屏
d.screen_off()

8.5 屏幕方向

# 設置屏幕方向
d.set_orientation(value)
# 獲取當前屏幕方向
d.orientation

value 值參考,只要是元組中的任一一個值就可以。

# 正常豎屏
(0, "natural", "n", 0), 
# 往左橫屏,相當於手機屏幕順時針旋轉 90 度
# 現實中如果要達到此效果,需要將手機逆時針旋轉 90 度
 (1, "left", "l", 90),
# 倒置,這個需要看手機系統是否支持 , 倒過來顯示 
 (2, "upsidedown", "u", 180), 
# 往右橫屏,調整與往左相反,屏幕順時針旋轉 270 度
 (3, "right", "r", 270))

8.6 打開通知欄與快速設置

打開通知欄

d.open_notification()

打開快速設置

d.open_quick_settings()

8.7 文件導入導出

8.7.1 導入文件

# 如果是目錄,這裡 "/sdcrad/" 最後一個斜槓一定要加,否則會報錯
d.push("test.txt","/sdcrad/")
d.push("test.txt","/sdcrad/test.txt")

8.7.2 導出文件

d.pull('/sdcard/test.txt','text.txt')

8.8 執行 shell 命令

使用 shell 方法執行

8.8.1 執行非阻塞命令

output 返回的是一個整體的字符串,如果需要抽取值,需要對 output 進行解析提取處理

# 返回輸出和退出碼,正常為 0,異常為 1
output,exit_code = d.shell(["ls","-l"],timeout=60)

8.8.2 執行阻塞命令(持續執行的命令)

# 返回一個命令的數據流 output 為 requests.models.Response
output = d.shell('logcat',stream=True)
try:
    # 按行讀取,iter_lines 為迭代響應數據,一次一行
    for line in output.iter_lines():
        print(line.decode('utf8'))
finally:
    output.close()

源碼描述

    def shell(self, cmdargs: Union[str, List[str]], stream=False, timeout=60):
        """
        Run adb shell command with arguments and return its output. Require atx-agent >=0.3.3

        Args:
            cmdargs: str or list, example: "ls -l" or ["ls", "-l"]
            timeout: seconds of command run, works on when stream is False
            stream: bool used for long running process.

        Returns:
            (output, exit_code) when stream is False
            requests.Response when stream is True, you have to close it after using

        Raises:
            RuntimeError

        For atx-agent is not support return exit code now.
        When command got something wrong, exit_code is always 1, otherwise exit_code is always 0
        """

8.9 session(目前已經被棄用)8.10 停止 UI2 服務

因為有 atx-agent 的存在,Uiautomator 會被一直守護著,如果退出了就會被重新啟動起來。但是 Uiautomator 又是霸道的,一旦它在運行,手機上的輔助功能、電腦上的 uiautomatorviewer 就都不能用了,除非關掉該框架本身的 uiautomator

使用代碼停止

d.service("uiautomator").stop()

手動停止

直接打開 ATX APP(init 成功後,就會安裝上),點擊關閉 UIAutomator

以上,歡迎大家一起交流探討。

推薦學習

推薦霍格沃茲出品 《測試開發實戰進階》課程,資深測試架構師、開源項目作者親授 BAT 大廠前沿最佳實踐。4 個月 20+ 項目實戰強化訓練,帶你一站式掌握 BAT 測試開發工程師必備核心技能(對標阿里P6+,年薪50W+)!學員直推 BAT 名企測試經理,普遍漲薪 50%+!

🔥14 期開課中🔥

相關焦點

  • uiautomator2+python自動化測試1-環境準備
    前言uiautomator是Google提供的用來做安卓自動化測試的一個Java庫。功能很強,可以對第三方App進行測試,獲取屏幕上任意一個APP的任意一個控制項屬性,並對其進行任意操作,但有兩個缺點:測試腳本只能使用Java語言測試腳本必須每次被上傳到設備上運行。
  • APP自動化測試系列之Appium介紹及運行原理
    >點擊上方藍字「ITester軟體測試小棧「關注我,每周一、三、五早上 08:30準時推送,每月不定期贈送技術書籍。微信公眾號後臺回復「資源」、「測試工具包」領取測試資源,回復「微信群」一起進群打怪。在面試APP自動化時,有的面試官可能會問Appium的運行原理,以下介紹Appium運行原理。
  • UI自動化測試框架
    本篇要講的是Android自動化測試框架UiAutomator。
  • 乾貨 | 一文搞定 pytest 自動化測試框架(一)
    簡介pytest 是一個成熟的全功能 Python 測試工具,可以幫助您編寫更好的程序。它與 Python 自帶的 Unittest 測試框架類似,但 pytest 使用起來更簡潔和高效,並且兼容 unittest 框架。
  • Python自動化測試踩坑記錄(企業中如何實施自動化測試)
    自動化主要分為兩大塊:UI與接口UI:Selenium  app:Appium / uiautomator2/airtest接口:Http  Postman   Requestswebsockets/dubbo比如說你先做UI自動化,你確定了這個方案,然後你可以根據業務側重點確認自動化覆蓋範圍和粒度。
  • 測試 | 如何用 Python 測試 Android 應用
    /p/8486863.html介紹uiautomator2 是一個可以使用Python對Android設備進行UI自動化的庫。其底層基於Google uiautomator,Google提供的uiautomator庫可以獲取屏幕上任意一個APP的任意一個控制項屬性,並對其進行任意操作,但有兩個缺點:1、測試腳本只能使用Java語言。2、測試腳本必須每次被上傳到設備上運行。 我們希望測試能夠用一個更腳本化的語言,例如Python編寫,同時可以每次所見即所得地修改測試、運行測試。
  • 移動APP自動化測試框架對比
    由於不支持iOS設備,當自動化測試同時覆蓋android與iOS的情況時,測試會被中斷。沒有內置的記錄和回放功能,使用記錄功能需要TestDroid和Robotium Recorder這樣的收費工具。http://www.oschina.net/translate/ios-ui-testing-with-kifKIF是Keep It Functional項目的縮寫,是一款iOS app功能性測試框架,使用Objective-C語言編寫,對蘋果開發者來說非常容易上手,更是一款開發者廣為推薦的測試工具。KIF tester使用私有API來了解App中的視圖層級。
  • 常用遊戲自動化測試工具
    目前網上搜自動化測試就會出現一大堆自動化測試的內容,但是並不詳細全面,今天就來說一下遊戲測試行業中的常用的遊戲測試自動化工具。一、Airtest的UI自動化測試工具Airtest是一款基於圖像識別和基於poco的UI控制項搜索框架的測試工具,因此會更適合遊戲和APP的測試。
  • 【收藏乾貨】基於Appium、Python的自動化測試環境部署和實踐
    1 導言1.1 編制目的該文檔為選用Appium作為行動裝置原生(Native)、混合(Hybrid)、移動Web(Mobile Web)應用UI自動化測試的相關自動化測試人員、開發人員等提供參考。1.2 預期讀者自動化測試人員、測試代表、開發人員等。
  • Android單元測試與模擬測試詳解
    一、測試與基本規範1. 為什麼需要測試?    更加易於維護,能夠在修改代碼後保證功能不被破壞。集成一些工具,規範開發規範,使得代碼更加穩定。2. 測什麼?    一般單元測試:列出想要測試覆蓋的異常情況,進行驗證。    模擬測試: 根據需求,測試用戶真正在使用過程中,界面的反饋與顯示以及一些依賴系統架構的組件的應用測試。3.
  • 2020年十大優秀的自動化測試工具
    Selenium是測試自動化的家喻戶曉的名字。它被認為是Web應用程式用戶界面自動化測試的行業標準。根據"測試自動化挑戰調查"顯示,十分之九的測試人員中有近九位在其項目中使用或曾經使用過硒。為了有效地使用Selenium,用戶必須具備高級編程技能,並且需要花費大量時間來構建自動化所需的自動化框架和庫。這是Selenium的主要缺點,可通過Katalon Studio等集成工具解決。許可證:開源2. Katalon Studio
  • 用於全棧自動化測試的最佳Python工具!
    Splinter是一個使用Python測試web應用程式的開源工具。它允許您自動化瀏覽器操作,例如訪問url並與它們的項進行交互。它使得編寫python Selenium測試更容易,因為它有一個高級API,可以讓您更容易地為瀏覽器應用程式開發自動化腳本。  如果您想使用Python進行測試自動化,那麼使用Robot框架是不會出錯的。
  • 5分鐘了解自動化測試,自動化優勢、劣勢、工具和框架選擇全剖析
    一、自動化測試基礎知識什麼是自動化測試1、把人為驅動的測試行為改成機器執行,通過設計的測試用例,由機器按照測試用例的執行步驟對其進行自動操作,輸出結果,由測試人員進行比較。2、自動化測試往往通過一些測試工具或框架,編寫自動化測試用例,來模擬手工測試。3、自動化測試能極大的節省人力、時間和硬體資源,提高測試效率。
  • 想要做自動化測試?八款高 Star 開源測試工具分享
    作為研發流程中的一環,測試環節的重要性不亞於產品研發,那麼今天 Gitee 推薦的就是有測試需求的開發者們,下面八款開源項目中包含了自動化測試平臺、熱數據探測框架、接口響應模擬系統以及 API 接口調試工具等,希望對在尋找測試工具的你有所幫助。
  • 微軟發布網頁自動化測試工具Playwright for Python
    微軟強化其端到端測試工具Playwright,使其不僅能夠使用JavaScript,對網頁應用程式進行測試,現在還擴張支持Python,讓Python開發者也能方便地,對網頁應用程式執行端到端測試。開發者可以從PyPI安裝Playwright for Python函數庫,開始測試工作。端到端測試是利用程序自動與UI交互,以驗證應用程式功能的方法,微軟提到,自動化端到端測試,可以讓開發團隊更快且更有自信地交付程序代碼,而且因為現在團隊交付速度要求更快,又需要構建可在多設備上執行的應用程式,所以測試的壓力也越來越大。
  • 一文教你使用Jenkins集成Junit自動化測試,超簡單!
    隨著技術的發展,Devops的概念越來越深入人心,Devops使得構建、測試、發布軟體能夠更加地快捷、頻繁和可靠。DevOps對應用程式發布的有著重要影響,具備DevOps能力則發布軟體產品時風險更低,其中一個重要的原因就是自動化,減少了人工幹預,強大的部署自動化手段確保部署任務的可重複性、減少部署出錯的可能性。
  • 自動化測試面試題
    你比較熟悉那種自動化測試工具?2. 你在你以前工作中是如何使用自動化測試工具的?3. 介紹一下你在利用自動化測試工具的過程中遇到的一些問題4. 你是如何計劃自動化測試的?5. 自動化測試能提高測試效率嗎?6. 什麼是data-driven automoation(數據啟動自動化)?7. 測試自動化的主要特徵有哪些?8.
  • 推薦10款 Java 程式設計師測試工具
    前言隨著DevOp的不斷流行,自動化測試慢慢成為Java開發者的關注點。因此,本文將分享10款優秀的單元測試框架和庫,它們可以幫助Java開發人員在其Java項目上編寫單元測試和集成測試。1. JUnit我絕對JUnit不需要太多的介紹了。即使您是Java初學者,也可能聽說過它。
  • APP 元素獲取工具—UI Automator
    UI Automator是一個UI測試框架,適用於跨系統和已安裝應用程式的跨應用程式功能性UI測試,需要Android4.3以上(APIlevel 18