Python+Appium自動化測試之toast定位

一,前言

在app自動化測試的過程中經(jīng)常會遇到需要對toast進(jìn)行定位,最常見的就是定位toast或者獲取toast的文案進(jìn)行斷言,如下圖,通過定位"登錄成功"的toast就可以斷言今日頭條登錄用例是否通過。但toast區(qū)別于控件元素,無法獲取焦點(diǎn),不能通過uiautomatorviewer.bat、appium、weditor等工具定位,因此我們就需要通過別的方法來定位。

今日頭條app登錄成功頁面

二,環(huán)境

  • windows 10
  • Android 10
  • appium 1.18.0 (desktop)
  • selenium 3.141.0
  • jdk 1.8

三,toast定位準(zhǔn)備與定位方法

1,準(zhǔn)備

注意:網(wǎng)上大量的博客都說定位toast需要使用uiautomator2,且需要安裝appium-uiautomator2-driver。但我在以上環(huán)境定位toast時(shí)是不需要uiautomator2,也無需安裝appium-uiautomator2-driver,且能定位成功?。?!大家可以嘗試,如果報(bào)錯(cuò)的話就老實(shí)按照下面步驟進(jìn)行吧。

  • 需要在Capablity里新增參數(shù)uiautomator2:
desired_caps['automationName'] = 'uiautomator2',
  • 再安裝appium-uiautomator2-driver,命令如下:
    cnpm install appium-uiautomator2-driver
    安裝成功后在C:\Users\xxx\node_modules會出現(xiàn)如下文件:
_appium-uiautomator2-driver@1.12.0@appium-uiautomator2-driver
_appium-uiautomator2-server@1.10.0@appium-uiautomator2-server

2,定位方法

toast需使用xpath的方式進(jìn)行定位

2.1,根據(jù)toast的文本內(nèi)容定位toast
driver.find_element_by_xpath('//*[@text="xxxxxx"]')

這種方式一般用于判斷或斷言是否出現(xiàn)文本為"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實(shí)例對象
    :param text: toast文本
    :param timeout: 定位超時(shí)時(shí)間
    :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.2,根據(jù)toast的屬性className定位toast

toast的className值為:android.widget.Toast

driver.find_element_by_xpath('//*[@class="android.widget.Toast"]')

這種方式一般用于獲取toast的文本內(nèi)容,封裝如下:

# -*- coding:utf-8 -*-
# @author: 給你一頁白紙

def get_toast_text(driver, timeout=20, poll_frequency=0.1):
    '''
    定位toast元素,獲取text屬性
    :param driver: driver實(shí)例對象
    :param timeout: 元素定位超時(shí)時(shí)間
    :param poll_frequency: 查詢頻率
    :return: toast文本內(nèi)容
    '''
    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,如果初始化構(gòu)造driver時(shí)已經(jīng)使用了隱式等待implicitly_wait(),則timeout參數(shù)可以不寫。

四,示例代碼

定位今日頭條app賬號密碼登錄成功后的 "登錄成功"toast
注意:我這里是將desired_caps里的Uiautomator2參數(shù)注釋掉了,且未安裝appium-uiautomator2-driver,也同樣能定位到,大家可在與我相同的環(huán)境下進(jìn)行嘗試。

# -*- 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,
        "noReset": 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()  # 點(diǎn)擊【同意】
        driver.find_element_by_id("com.ss.android.article.news:id/cji").click() # 點(diǎn)擊【我知道了】
        driver.find_element_by_id("android:id/button1").click() # 點(diǎn)擊權(quán)限管理-確定按鈕
        driver.find_element_by_xpath("http://android.widget.TabWidget/android.widget.RelativeLayout[@index=3]").click() # 點(diǎn)擊未登錄
        driver.find_element_by_id("com.ss.android.article.news:id/a10").click() # 未登錄頁點(diǎn)擊登錄按鈕
        driver.find_element_by_id("com.ss.android.article.news:id/bgh").click() # 登錄頁點(diǎn)擊“。。。”
        driver.find_element_by_xpath("http://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() # 點(diǎn)擊登錄
    except Exception as e:
        print("登錄錯(cuò)誤,原因?yàn)椋簕}".format(e))
        # 報(bào)錯(cuò)時(shí)截圖
        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)

運(yùn)行結(jié)果如下,說明定位該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
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容