移動端自動化測試框架Appium

啓動過程

appium的啓動實際上是在本機使用了4723端口開啓了一個服務

1. 我們寫的 python 代碼會訪問本機的 appium 服務器,並獲取 driver 對象

2. appium 會將我們的 driver 對象調用的方法轉化成 post 請求,提交給appium服務器

3. appium 通過接收到的 post 請求發送給手機,再由手機進行執行

# 導模塊 
from appium import webdriver 
# 創建一個字典,包裝相應的啓動參數 
desired_caps = dict() 
# 需要連接的手機的平臺(不限制大小寫) 
desired_caps['platformName'] = 'Android' 
# 需要連接的手機的版本號(比如 5.2.1 的版本可以填寫 5.2.1 或 5.2 或 5 ,以此類推) desired_caps['platformVersion'] = '5.1' 
# 需要連接的手機的設備號(andoird平臺下,可以隨便寫,但是不能不寫) 
desired_caps['deviceName'] = '192.168.56.101:5555' 
# 需要啓動的程序的包名 
desired_caps['appPackage'] = 'com.android.settings' 
# 需要啓動的程序的界面名 
desired_caps['appActivity'] = '.Settings' 
# 連接appium服務器 
driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps) 
# 退出 
driver.quit()

App基礎操作API

import os

from app.util import encode_data, decode_data, get_driver

driver = get_driver()

"3、app是否已安裝"
is_installed = driver.is_app_installed('com.example.corel.calc')
# eg:沒安裝安裝,安裝了就卸載
if is_installed:
    "2、卸載手機自己安裝的app,不能卸載系統的app"
    driver.remove_app('com.example.corel.calc')
else:
    "1、安裝apk到手機,支持重複安裝進行覆蓋,絕對路徑"
    driver.install_app(os.getcwd() + os.sep + 'apk' + os.sep + 'com.example.corel.calc_2.1.1023_11.apk')


"""4、發送⽂件到⼿機,eg:將hello寫入到手機
    driver.push_file(path, data)
        參數:
            path:⼿機設備上的路徑(例如:/sdcard/a.txt)
            data:⽂件內數據,要求base64編碼
            Python3.x中字符都爲unicode編碼,⽽b64encode函數的參數爲byte類型,需要先轉碼;⽣成的數據爲byte類型,需要將byte轉換回去。"""

data = encode_data('hello')
driver.push_file('/sdcard/abc.txt', data)  # 不指定abc.txt,會生成一個.tmp結尾的臨時文件,不便於後續的維護

"5、從手機拉取文件,返回的是base64編碼數據"
data = driver.pull_file('/sdcard/abc.txt')   # 返回數據爲base64編碼
re_data = decode_data(data)
print(re_data)

"6、獲取 當前屏幕 元素結構,返回xml字符串,只是當前屏幕(activity頁面內容是xml承載的)"
with open('./result/page.xml', 'w') as f:
    f.write(driver.page_source)

driver.quit()
import base64

from appium import webdriver


# 輸⼊⽂本內容到⼿機,中文輸入支持:
#   1 使用Unicode鍵盤:'unicodeKeyboard': True
#   2 重置鍵盤:'resetKeyboard': True

def get_driver():
    desired_caps = {'platformName': 'android',
                    'platformVersionName': '5.1',
                    'deviceName': '192.168.192.101:5555',
                    'appPackage': 'com.android.settings',
                    'appActivity': '.Settings',
                    'unicodeKeyboard': True}
    return webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)


# base64編碼
def encode_data(value_arg):
    return str(base64.b64encode(value_arg.encode('utf-8')), 'utf-8')


# base64解碼
def decode_data(data):
    return str(base64.b64decode(data), 'utf-8')

APP元素定位操作

appium常用元素定位方式

name

value

id

resource-id屬性值

class

class屬性值

xpath

xpath表達式

from time import sleep
from selenium.webdriver.support.wait import WebDriverWait

#   ❀ 藉助sdk家⽬錄下的tools⽬錄中的uiautomatorviewer.bat進行定位,而該shell腳本和appium共用同一個adb,
# 如果自動化腳本中因異常沒有關閉adb服務,那此時進行快照截圖的話是會報錯的,解決辦法:adb kill-server
# 三種定位使用優先級:
#     優先使用:id class
#     其次使用:xpath,需藉助text、class、resource-id纔可完成

# xpath語句:
#  1."//*[contains(@text,'text屬性值')]"
#  2."//*[contains(@class,'class屬性值')]"
#  3."//*[contains(@resource-id,'resource-id屬性值')]"
from app.util import get_driver

driver = get_driver()
# 1、id獲取搜索按鈕並點擊
driver.find_element_by_id('com.android.settings:id/search').click()

# 3.1 xpath + id組合 獲取搜索按鈕並點擊
search_btn = '//*[contains(@resource-id, "com.android.settings:id/search")]'
driver.find_element_by_xpath(search_btn).click()
sleep(2)

# 2、class獲取返回按鈕並點擊
driver.find_element_by_class_name('android.widget.ImageButton').click()

# 3.2 xpath + class組合 獲取返回按鈕並點擊
search_return_btn = '//*[contains(@class, "android.widget.ImageButton")]'
driver.find_element_by_xpath(search_return_btn).click()
sleep(2)

# 3.3 xpath + text 獲取返回按鈕並點擊
more_btn = '//*[contains(@text, "更")]'
driver.find_element_by_xpath(more_btn).click()
sleep(2)

# 定位一組元素id,class,xpath
ids_value = driver.find_elements_by_id('com.android.settings:id/title')
for i in ids_value:
    print(i.text)

print('❀______')

classes_value = driver.find_elements_by_class_name('android.widget.TextView')
for i in classes_value:
    print(i.text)

print('❀______')

xpath_value = '//*[contains(@text, "示")]'
xpaths_value = driver.find_elements_by_xpath(xpath_value)
for i in xpaths_value:
    print(i.text)

# 隱式等待:是等到整個頁面加載結束才進行後續操作
# 顯示等待:是等待某一個具體的元素成功獲取
driver.find_element_by_xpath('//*[contains(@text, "更多")]').click()
WebDriverWait(driver, 10).until(lambda x: x.find_element_by_xpath('//*[contains(@text, "飛行模式")]')).click()

driver.quit()

APP元素信息操作API

from app.util import get_driver

driver = get_driver()

search = driver.find_element_by_id('com.android.settings:id/search')
search.click()
search_input = driver.find_element_by_id('android:id/search_src_text')
search_input.send_keys('文')
search_input.clear()
search_input.send_keys('星魂')

# 獲取元素id class text content-desc的屬性值:
# get_attribute(value):
#     value = name -> 返回content-desc或text
#     value = text -> 返回text
#     value = className -> 返回class,只有API>=18(Android4.3)才能支持
#     value = resourceId -> 返回resource_id,只有API>=18才能支持

print('resource_id:', search.get_attribute('resourceId'))
print('class:', search.get_attribute('className'))
print('content_desc:', search.get_attribute('name'))

# 應用場景:只是想滑動輪播圖,並不想整個頁面滑動
more_btn = '//*[contains(@text, "更")]'
more = driver.find_element_by_xpath(more_btn)
# 1 獲取元素屏幕座標
print('座標:' + more.location)
# 2 獲取元素大小
print('寬和高:' + more.size)


# 獲取包命和啓動名
print('包命:', driver.current_package)
print('啓動名:', driver.current_activity)

driver.quit()

APP元素事件操作API

swipe滑動事件

import time

from util import get_driver

# swipe(start_x, start_y, end_x, end_y, duration=None),duration單位ms
# 作用:
#   1 滑動沒有持續時間,滑動相對隨機,隨機距離不遠
#   2 滑動持續在2s左右時,滑動相對準確  --最常用
#   3 滑動持續爲幾十毫秒時,會產生點擊起點位置操作

driver = get_driver()

save = driver.find_element_by_xpath("//*[contains(@text,'存儲')]").location
wlan = driver.find_element_by_xpath("//*[contains(@text,'WLAN')]").location

# driver.swipe(save.get("x"), save.get("y"), wlan.get("x"), wlan.get("y"))

# 滑動,有滑動時間,滑動相對準確 最少2s
driver.swipe(save.get("x"), save.get("y"), wlan.get("x"), wlan.get("y"), 2000)

# 滑動,有滑動時間,滑動相對較長 最少200ms  但如果時幾十毫秒,會產生點擊起點位置操作
driver.swipe(save.get("x"), save.get("y"), wlan.get("x"), wlan.get("y"), 200)

# 關閉
time.sleep(2)
driver.quit()

scroll滑動事件

import time

from util import get_driver

# scroll(origin_el, destination_el, duration=None)
# 滑動相對隨機,不用

driver = get_driver()

save = driver.find_element_by_xpath("//*[contains(@text,'存儲')]").location
wlan = driver.find_element_by_xpath("//*[contains(@text,'WLAN')]").location

# 無滑動時間
driver.scroll(save, wlan)
# 有滑動時間2s
driver.scroll(save, wlan, 2000)

# 關閉
time.sleep(2)
driver.quit()

drag拖拽事件

import time

from util import get_driver

# drag_and_drop(origin_el, destination_el):從⼀個元素滑動到另⼀個元素,起點元素最終會替代終點元素原本屏幕上的位置

driver = get_driver()

save = driver.find_element_by_xpath("//*[contains(@text,'存儲')]").location
wlan = driver.find_element_by_xpath("//*[contains(@text,'WLAN')]").location

driver.drag_and_drop(save, wlan)

# 關閉
time.sleep(2)
driver.quit()
from time import sleep

from appium.webdriver.common.touch_action import TouchAction

from util import get_driver

driver = get_driver()

save = driver.find_element_by_xpath("//*[contains(@text,'存儲')]")
more = driver.find_element_by_xpath("//*[contains(@text,'更多')]")

touch_action = TouchAction(driver)

# 滑動方式一:press(元素).move_to(元素)  滑動不精準,scroll底層實現方式
touch_action.press(save).move_to(more).release().perform()
# 滑動方式二:press(座標).move_to(座標)  滑動不精準,swipe底層實現方式
touch_action.press(x=save.location.get('x'), y=save.location.get('y')).move_to(x=more.location.get('x'),
                                                                               y=more.location.get(
                                                                                   'y')).release().perform()
# 滑動方式三:long_press(元素).move_to(座標)  精準滑動,drag_and_drop底層實現方式
touch_action.long_press(save).move_to(more).release().perform()

sleep(2)
driver.quit()

 

應⽤置於後臺事件

from time import sleep

from util import get_driver

driver = get_driver()
sleep(1)

# 將設置app放置後臺5s,在此期間,點擊桌面應用無效,因爲它並沒有運行結束,而是在後臺運行
driver.background_app(5)

driver.quit()

APP模擬⼿勢⾼級操作

TouchAction是AppiumDriver的輔助類,主要針對⼿勢操作,⽐如滑動、⻓按、拖動等, 原理是將⼀系列的動作放在⼀個鏈條中 發送 到服務器,服務器接受到該鏈條後,解析各個動作,逐個執⾏

from time import sleep

from appium.webdriver.common.touch_action import TouchAction

from util import get_driver

driver = get_driver()

wlan = driver.find_element_by_xpath("//*[contains(@text,'WLAN')]")
touch_action = TouchAction(driver)

"""1 手指輕敲操作:模擬⼿指輕敲⼀下屏幕操作"""
# TouchAction(driver).tap(wlan).perform()  # 元素方式
touch_action.tap(x=wlan.location.get('x'), y=wlan.location.get('y')).perform() # 座標方式

"""2 ⼿指按操作:: 模擬⼿指按下屏幕,然後鬆開"""
touch_action.press(wlan).release().perform()  # 元素方式
touch_action.press(x=wlan.location.get('x'), y=wlan.location.get('y')).perform() # 座標方式

"""3 等待操作:wait(ms=0)"""
# 方式一:press + wait
wlan.click()
ssid = driver.find_element_by_xpath("//*[contains(@text,'SSID')]")
# 添加等待(有⻓按)/不添加等待(⽆⻓按效果)
touch_action.press(ssid).wait(2000).release().perform()

# 方式二:long_press
touch_action.long_press(ssid).release().perform()  # 元素方式
touch_action.long_press(x=ssid.location.get('x'), y=wlan.location.get('y')).release().perform()  # 座標方式


sleep(2)
driver.quit()
from time import sleep

from appium.webdriver.common.touch_action import TouchAction

from util import get_driver

# appium版本 1.12
#   move_to:絕對座標
# appium版本 1.7之前
#   move_to:相對座標

driver = get_driver()
bat = driver.find_element_by_xpath("//*[contains(@text,'電池')]")
wlan = driver.find_element_by_xpath("//*[contains(@text,'WLAN')]")

driver.drag_and_drop(bat, wlan)
driver.find_element_by_xpath("//*[contains(@text,'安全')]").click()
sleep(2)
driver.find_element_by_xpath("//*[contains(@text,'屏幕鎖定')]").click()
sleep(2)
driver.find_element_by_xpath("//*[contains(@text,'圖案')]").click()

sleep(2)

TouchAction(driver).press(x=234, y=850).wait(100).move_to(x=723, y=850).wait(100) \
    .move_to(x=723, y=1326).wait(100).move_to(x=234, y=1808).release().perform()

sleep(2)
driver.quit()

⼿機操作API

from time import sleep

from util import get_driver

driver = get_driver()

# 1 獲取手機分辨率,通常用於swipe方法完成滑動操作
size = driver.get_window_size()
print('分辨率:', size)

width = size.get('width')
height = size.get('height')

driver.swipe(width * 0.5, height * 0.8, width * 0.5, height * 0.2, 2000)

sleep(3)
driver.close_app()
driver.swipe(width * 0.8, height * 0.5, width * 0.2, height * 0.5, 2000)

sleep(3)
driver.quit()

 發送鍵到設備

from time import sleep

from util import get_driver

driver = get_driver()

# 模擬音量鍵 +
for i in range(3):
    driver.keyevent(24)
# 模擬音量鍵 -
for i in range(3):
    driver.keyevent(25)

sleep(3)
driver.quit()

 操作⼿機通知欄

from appium import webdriver
import time

# server 啓動參數
from appium.webdriver.common.touch_action import TouchAction

desired_caps = {}
# 設備信息
desired_caps['platformName'] = 'Android'
desired_caps['platformVersion'] = '5.1'
desired_caps['deviceName'] = '192.168.56.101:5555'
# app的信息
desired_caps['appPackage'] = 'io.manong.developerdaily'
desired_caps['appActivity'] = 'io.toutiao.android.ui.activity.MainActivity'
# 聲明我們的driver對象
driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)

# 打開通知欄
driver.open_notifications()
# 獲取時間 id
value = driver.find_element_by_id("com.android.systemui:id/date_expanded").text
print("時間爲:", value)

time.sleep(2)
driver.quit()

獲取⼿機當前⽹絡

from appium import webdriver
import time

# server 啓動參數
from appium.webdriver.common.touch_action import TouchAction

desired_caps = {}
# 設備信息
desired_caps['platformName'] = 'Android'
desired_caps['platformVersion'] = '5.1'
desired_caps['deviceName'] = '192.168.56.101:5555'
# app的信息
desired_caps['appPackage'] = 'com.android.settings'
desired_caps['appActivity'] = '.Settings'
# 聲明我們的driver對象
driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)

# 打印手機網絡狀態
print("當前網絡爲:", driver.network_connection)

# 修改手機網絡 data
driver.set_network_connection(4)
# 打印手機網絡狀態
print("當前網絡爲:", driver.network_connection)

# 修改手機網絡
driver.set_network_connection(2)
# 打印手機網絡狀態
print("當前網絡爲:", driver.network_connection)

# 修改手機網絡
driver.set_network_connection(1)
# 打印手機網絡狀態
print("當前網絡爲:", driver.network_connection)






time.sleep(2)
driver.quit()

⼿機截圖

from appium import webdriver
import time

# server 啓動參數
from appium.webdriver.common.touch_action import TouchAction

desired_caps = {}
# 設備信息
desired_caps['platformName'] = 'Android'
desired_caps['platformVersion'] = '5.1'
desired_caps['deviceName'] = '192.168.56.101:5555'
# app的信息
desired_caps['appPackage'] = 'com.android.settings'
desired_caps['appActivity'] = '.Settings'
# 聲明我們的driver對象
driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)

# 截圖
driver.get_screenshot_as_file("{}.png".format(int(time.time())))   # 1583378495 不加int:1583378546.1369514

time.sleep(2)
driver.quit()

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章