Python+Appium自動化測試之定位toast
阿新 • • 發佈:2020-09-21
一,前言
在app自動化測試的過程中經常會遇到需要對toast進行定位,最常見的就是定位toast或者獲取toast的文案進行斷言,如下圖,通過定位"登入成功"的toast就可以斷言今日頭條登入用例是否通過。但toast區別於控制元件元素,無法獲取焦點,不能通過uiautomatorviewer.bat、appium、weditor等工具定位,因此我們就需要通過別的方法來定位。
二,環境
- windows 10
- Android 10
- appium 1.18.0 (desktop)
- selenium 3.141.0
- jdk 1.8
三,toast定位準備與定位方法
準備
注意:網上大量的部落格都說定位toast需要使用uiautomator2,且需要安裝appium-uiautomator2-driver。但我在以上環境定位toast時是不需要uiautomator2,也無需安裝appium-uiautomator2-driver,且能定位成功!!!大家可以嘗試,如果報錯的話就老實按照下面步驟進行吧。
- 需要使用uiautomator2,即在Capablity裡新增引數:
desired_caps['automationName'] = 'uiautomator2',
- 安裝appium-uiautomator2-driver,命令如下:
cnpm install appium-uiautomator2-driver
安裝成功後在C:\Users\xxx\node_modules會出現如下檔案:
[email protected]@appium-uiautomator2-driver [email protected]@appium-uiautomator2-server
定位方法
toast需使用xpath的方式進行定位
1,根據toast的文字內容定位toast
driver.find_element_by_xpath('//*[@text="xxxxxx"]')
這種方式一般用於判斷或斷言是否出現文字為"xxxxxx"的toast,因此我們可以封裝如下:
# -*- coding:utf-8 -*- # @author: 給你一頁白紙 from selenium.webdriver.support import expected_conditions as ec from selenium.webdriver.support.ui import WebDriverWait from appium.webdriver.common.mobileby import MobileBy as By def is_toast_exist(driver, text, timeout=20, poll_frequency=0.1): ''' 判斷toast是否存在,是則返回True,否則返回False :param driver: driver例項物件 :param text: toast文字 :param timeout: 定位超時時間 :param poll_frequency: 查詢頻率 :return: True or False ''' try: toast_loc = (By.XPATH, ".//*[contains(@text, %s)]" % text) WebDriverWait(driver, timeout, poll_frequency).until( ec.presence_of_element_located(toast_loc) ) return True except: return False
2,根據toast的屬性className定位toast
toast的className值為:android.widget.Toast
driver.find_element_by_xpath('//*[@class="android.widget.Toast"]')
這種方式一般用於獲取toast的文字內容,封裝如下:
# -*- coding:utf-8 -*-
# @author: 給你一頁白紙
def get_toast_text(driver, timeout=20, poll_frequency=0.1):
'''
定位toast元素,獲取text屬性
:param driver: driver例項物件
:param timeout: 元素定位超時時間
:param poll_frequency: 查詢頻率
:return: toast文字內容
'''
toast_loc = (By.XPATH, '//*[@class="android.widget.Toast"]')
try:
toast = WebDriverWait(driver, timeout, poll_frequency).until(
ec.presence_of_element_located(toast_loc)
)
toast_text = toast.get_attribute('text')
return toast_text
except Exception as e:
return e
- 注意:
1,等待方式只能用presence_of_element_located(),即只能其存在,而不能等待其可見。
2,如果初始化構造driver時已經使用了隱式等待implicitly_wait(),則timeout引數可以不寫。
四,示例程式碼
定位今日頭條app賬號密碼登入成功後的 "登入成功"toast
注意:我這裡是將desired_caps裡的automationName引數註釋掉了,也同樣能定位到,大家可在與我相同的環境下進行嘗試。
# -*- coding:utf-8 -*-
# @author: 給你一頁白紙
from appium import webdriver
from selenium.webdriver.support import expected_conditions as ec
from selenium.webdriver.support.ui import WebDriverWait
from appium.webdriver.common.mobileby import MobileBy as By
def android_driver():
desired_caps = {
"platformName": "Android",
"platformVersion": "10",
"deviceName": "PCT_AL10",
"appPackage": "com.ss.android.article.news",
"appActivity": ".activity.MainActivity",
# "automationName": "UiAutomator2",
"unicodeKeyboard": True,
"resetKeyboard": True,
"restart": True,
}
# 啟動app
driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
return driver
def is_toast_exist(driver, text, timeout=20, poll_frequency=0.1):
'''
判斷toast是否存在,是則返回True,否則返回False
'''
try:
toast_loc = (By.XPATH, ".//*[contains(@text, %s)]" % text)
WebDriverWait(driver, timeout, poll_frequency).until(
ec.presence_of_element_located(toast_loc)
)
return True
except:
return False
def get_toast_text(driver, timeout=20, poll_frequency=0.1):
'''
定位toast元素,獲取text屬性
'''
toast_loc = (By.XPATH, '//*[@class="android.widget.Toast"]')
try:
toast = WebDriverWait(driver, timeout, poll_frequency).until(
ec.presence_of_element_located(toast_loc)
)
toast_text = toast.get_attribute('text')
return toast_text
except Exception as e:
return e
def login_opera(driver):
'''登入今日頭條操作'''
try:
# driver.find_element_by_id("com.ss.android.article.news:id/cji").click() # 點選【同意】
driver.find_element_by_id("com.ss.android.article.news:id/cji").click() # 點選【我知道了】
driver.find_element_by_id("android:id/button1").click() # 點選許可權管理-確定按鈕
driver.find_element_by_xpath("//android.widget.TabWidget/android.widget.RelativeLayout[@index=3]").click() # 點選未登入
driver.find_element_by_id("com.ss.android.article.news:id/a10").click() # 未登入頁點選登入按鈕
driver.find_element_by_id("com.ss.android.article.news:id/bgh").click() # 登入頁點選“。。。”
driver.find_element_by_xpath("//android.widget.LinearLayout[@index=4]").click() # 選擇密碼登入
driver.find_element_by_id("com.ss.android.article.news:id/bu").send_keys("xxxxxxxx") # 輸入賬號
driver.find_element_by_id("com.ss.android.article.news:id/c5").send_keys("xxxxxxxx") # 輸入密碼
driver.find_element_by_id("com.ss.android.article.news:id/a2o").click() # 點選登入
except Exception as e:
print("登入錯誤,原因為:{}".format(e))
# 報錯時截圖
driver.get_screenshot_as_file(r'E:\blog\blog_script\images\test_login_error_01.png')
else:
toast_text = get_toast_text(driver)
print(toast_text)
toast_el = is_toast_exist(driver, "登入成功")
print(toast_el)
if __name__ == '__main__':
driver = android_driver()
login_opera(driver)
執行結果如下,說明定位該toast成功:
C:\Users\xiaoqq\AppData\Local\Programs\Python\Python37\python.exe E:/blog/blog_script/login_jrtt.py
登入成功
True
Process finished with exit code 0