一、什么是元素等待
元素等待的意义
- 在 Appium 自动化测试中,元素等待是一个重要的环节。当脚本执行速度较快,而页面元素尚未加载完成时,就会导致脚本无法定位到元素,从而使执行失败。因此需要设置元素等待,从而增强脚本的健壮性,提高执行效率。
- 元素等待的主要目的是确保在执行操作之前,目标元素已经在界面上可用。这样可以避免因元素未加载完成而导致的错误。
在使用元素等待时,需要注意以下几点:
- 等待时间的设置要合理,过长的等待时间会影响测试效率,过短可能导致等待失败。
- 对于一些复杂的页面或网络环境较差的情况,可能需要适当增加等待时间。
以下是一些常见的元素等待方法:
- WebDriverWait:可以设置等待时间和超时时间,在指定时间内等待元素出现。
- 显式等待:通过明确指定要等待的条件来等待元素。
- 隐式等待:在查找元素时设置一个全局的等待时间,在该时间内查找元素。
二、元素等待的方法
方法一
定义方法:
from selenium.webdriver.support.ui import WebDriverWait
# 定义一个获取元素的方法
def get_element(driver, element):
wait = WebDriverWait(driver, 10, 1)
# element = wait.until(lambda x: x.find_element(element[0], element[1]))
element = wait.until(lambda x: x.find_element(*element))
return element
方式解释:
这段代码是在使用 Selenium 库中的 WebDriverWait 类。
- WebDriverWait(driver, 10, 1):创建一个等待对象 wait。其中:
-
- driver:驱动对象。
- 10:表示等待的最大时间(以秒为单位)。
- 1:表示每隔 1 秒检查一次条件。
- wait.until(lambda x: x.find_element(*element)):使用 until 方法等待某个条件满足。这里的条件是通过一个 lambda 函数定义的,该函数使用 driver 对象的 find_element 方法来查找指定的元素。
这段代码的目的是在最多等待 10 秒的时间内,每隔 1 秒检查一次,直到找到指定的元素。找到元素后,将其赋值给 element 变量。
通过设置等待时间和超时时的时间间隔,可以在执行操作之前确保网页已经加载完成,或者特定元素已经处于可用状态。
这样可以避免在元素尚未准备好时尝试与之交互而导致的错误。
方法应用:
下面是一个示例,使用上述显示等待的方法获取元素后,即使不使用time.sleep()方法进行等待,代码仍然可以正常执行:
import time
from appium import webdriver
from appium.options.android import UiAutomator2Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
# 定义一个获取元素的方法
def get_element(driver, element):
wait = WebDriverWait(driver, 10, 1)
element = wait.until(lambda x: x.find_element(*element))
return element
# 定义一个初始化APP的方法
def start_app(app_package, app_activity):
# 定义desired_caps 字典,初始化app的配置信息
desired_caps = {
"platformName": "android", # 表示的是android
"platformVersion": "10", # 表示的是设备系统的版本号
"deviceName": "DWV6R19A10002101", # 表示的是设备的ID名称
"appPackage": app_package, # 表示的是app的包名
"appActivity": app_activity, # 表示的是app的界面名
"newCommandTimeout": 100000,
"noReset": True
}
# 创建 Appium 驱动实例
options = UiAutomator2Options().load_capabilities(desired_caps)
driver = webdriver.Remote("http://localhost:4723/wd/hub", options=options)
# 启动应用程序
driver.wait_activity(desired_caps, 5)
# 返回驱动实例
return driver
if __name__ == "__main__":
# 本次启动的应用程序包名和活动名(作业帮)
app_package_zyb = "com.baidu.homework"
app_activity_zyb = ".activity.index.IndexActivity"
# 启动应用程序
driver_zyb = start_app(app_package_zyb, app_activity_zyb)
# 通过元素id来进行元素定位,定位到作业批改年级选择框并点击
grade_element = (By.ID, "com.baidu.homework:id/user_grade")
grade_select = get_element(driver_zyb, grade_element)
if grade_select.is_displayed():
grade_select.click()
print("grade_select clicked")
else:
print("grade_select not found or not displayed")
# 通过XPATH来进行元素定位,定位到六年级并点击,设置年级成功
grade_xpath = By.XPATH, "//android.widget.TextView[@resource-id='com.baidu.homework:id/gradeName' and @text='六年级']"
grade_set = get_element(driver_zyb, grade_xpath)
if grade_set.is_displayed():
grade_set.click()
print("grade_set clicked")
else:
print("grade_set not found or not displayed")
# 通过CLASS_NAME定位到"我的"并点击,进入我的tab页
# 下面代码如果不加上time.sleep()可能会报错,可以使用方法二来避免
time.sleep(3)
class_path = By.CLASS_NAME, "android.widget.ImageView"
may_tab = get_element(driver_zyb, class_path)
if may_tab.is_displayed():
may_tab.click()
print("may_tab clicked")
else:
print("may_tab not found or not displayed")
# 停止应用程序,退出驱动
time.sleep(5)
print("代码执行结束")
driver_zyb.quit()
方法二
定义方法:
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# 定义一个获取元素的方法
def get_element_new(driver, element):
element = WebDriverWait(driver, 10).until(EC.visibility_of_element_located(element))
return element
方法解释:
这段代码是在使用 Selenium 库中的 WebDriverWait 方法来等待一个元素可见。
具体解释如下:
- driver:驱动对象。
- 10:表示等待的时间(单位是秒)。
- expected_conditions.visibility_of_element_located(element):是期望的条件,即等待指定的元素可见。
这段代码的作用是在指定的时间内(10 秒)等待元素可见。如果在等待时间内元素可见,则代码继续执行;如果超过等待时间元素仍不可见,则会抛出异常。
通过使用 WebDriverWait 和期望条件,可以增加测试的稳定性和可靠性,以确保在执行后续操作之前元素处于所需的状态。
方法应用:
import time
from appium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from appium.options.android import UiAutomator2Options
from selenium.webdriver.support import expected_conditions as EC
# 定义一个获取元素的方法
def get_element_new(driver, element):
element = WebDriverWait(driver, 10).until(EC.visibility_of_element_located(element))
return element
# 定义一个初始化APP的方法
def start_app(app_package, app_activity):
# 定义desired_caps 字典,初始化app的配置信息
desired_caps = {
"platformName": "android", # 表示的是android
"platformVersion": "10", # 表示的是设备系统的版本号
"deviceName": "DWV6R19A10002101", # 表示的是设备的ID名称
"appPackage": app_package, # 表示的是app的包名
"appActivity": app_activity, # 表示的是app的界面名
"newCommandTimeout": 100000,
"noReset": True
}
# 创建 Appium 驱动实例
options = UiAutomator2Options().load_capabilities(desired_caps)
driver = webdriver.Remote("http://localhost:4723/wd/hub", options=options)
# 启动应用程序
driver.wait_activity(desired_caps, 5)
return driver
if __name__ == "__main__":
# 本次启动的应用程序包名和活动名(作业帮)
app_package_zyb = "com.baidu.homework"
app_activity_zyb = ".activity.index.IndexActivity"
# 启动应用程序
driver_zyb = start_app(app_package_zyb, app_activity_zyb)
# 通过元素id来进行元素定位,定位到作业批改年级选择框并点击
element = (By.ID, 'com.baidu.homework:id/user_grade')
grade_select = get_element_new(driver_zyb, element)
if grade_select.is_displayed():
grade_select.click()
print("grade_select clicked")
else:
print("grade_select not found or not displayed")
# 通过XPATH来进行元素定位,定位到六年级并点击,设置年级成功
element = (By.XPATH, '//android.widget.TextView[@resource-id="com.baidu.homework:id/gradeName" and @text="六年级"]')
grade_set = get_element_new(driver_zyb, element)
if grade_set.is_displayed():
grade_set.click()
print("grade_set clicked")
else:
print("grade_set not found or not displayed")
# 通过CLASS_NAME定位到"我的"并点击,进入我的tab页
element = (By.CLASS_NAME, "android.widget.ImageView")
may_tab = get_element_new(driver_zyb, element)
if may_tab.is_displayed():
may_tab.click()
print("may_tab clicked")
else:
print("may_tab not found or not displayed")
# 关闭浏览器
time.sleep(3)
print("代码执行完毕")
driver_zyb.quit()
未完待续……