我们在前面遇到过定位元素时元素还未载入成功,然后定位失败的情况,当这种情况时,我们需要等待元素出现。可以用4种方法

1、强制等待

所谓强制等待就是直接sleep,代码如下

import time 
time.sleep(10)

强制等待存在几个问题

  • 无论后面步骤元素是否可以定位,都必须等待设置的时间,非常影响自动化测试的效率
  • 时间长短不好把握,设长了影响测试的效率,设短了可能元素还未载入成功,导致执行失败

所以一般不建议使用强制等待

2、隐式等待implicitly_wait()

隐式等待的方法是全局设置,存货与webdriver对象的生命周期,设置代码如下

driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", caps)
driver.implicitly_wait(10)

隐式等待是在定位元素时,等到页面所有元素都加载成功后才执行下一步,如果超时时间未定位到元素则抛异常。

隐式等待也存在一些问题

  • 当定位的元素已经出来时,页面元素未加载成功,还是会一直等待,影响测试效率
  • 抛的异常无法自己设置(如下为关键异常信息),不容易看出是什么元素出问题
selenium.common.exceptions.NoSuchElementException: Message: An element could not be located on the page using the given search parameters.

3、用wait_activity()等待页面出现

当操作为一个元素下一个元素迟迟不出现的情况肯定是切好页面了,所以也可以用wait_activity()来等待预期出现的activity出现后再做下一步元素定位操作。

示意代码如下

#点击记一笔按钮
#time.sleep(5)
add_trans_btn = driver.find_element(AppiumBy.ID,"com.mymoney:id/add_trans_btn") 
print("add_trans_btn 的文本是,",add_trans_btn.text)
add_trans_btn.click()
#上述操作后跳转到新的activity,com.mymoney.biz.addtrans.activity.AddTransActivityV12
#等待页面出现
driver.wait_activity(“com.mymoney.biz.addtrans.activity.AddTransActivityV12”)

此方法也有一些问题

  • 需要知道操作后下一个activity的名字,操作起来耗费时间
  • 有时候activity虽然出现了,可是我们要定位的元素还是没载入成功,最后还是会失败

4、显示等待WebDriverWait()

WebDriverWait()可以应用到确切的元素,而且可以设置抛出异常的类型和抛出异常的消息,方便进行定位

WebDriverWait需要配合until或until_not使用,until用于等待元素出现,until_not用于等待元素消失。

WebDriverWait需要通过“from selenium.webdriver.support.wait import WebDriverWait”引用。

参数说明:

  • driver:浏览器驱动,需要传入该参数
  • timeout:最长超时时间,默认以秒为单位,必须传入该参数
  • poll_frequency:检测的间隔步长,默认为0.5s,可以不传
  • ignored_exceptions:超时后的抛出的异常信息,默认抛出NoSuchElementExeception异常,可以不传

until参数说明:

:param method: callable(WebDriver),可以用自定义方法,也可以使用expected_conditions

:param message: optional message for :exc:`TimeoutException`,默认是空字符串,此处可以设置在失败是我们希望看到的错误信息,便于定位问题

方法说明
title_is判断当前页面的 title 是否完全等于(==)预期字符串,返回布尔值
title_contains判断当前页面的 title 是否包含预期字符串,返回布尔值
presence_of_element_located判断某个元素是否被加到了 dom 树里,并不代表该元素一定可见
visibility_of_element_located判断元素是否可见(可见代表元素非隐藏,并且元素宽和高都不等于 0)
visibility_of同上一方法,只是上一方法参数为locator,这个方法参数是 定位后的元素
presence_of_all_elements_located判断是否至少有 1 个元素存在于 dom 树中。举例:如果页面上有 n 个元素的 class 都是’wp’,那么只要有 1 个元素存在,这个方法就返回 True
text_to_be_present_in_element判断某个元素中的 text 是否 包含 了预期的字符串
text_to_be_present_in_element_value判断某个元素中的 value 属性是否包含 了预期的字符串
frame_to_be_available_and_switch_to_it判断该 frame 是否可以 switch进去,如果可以的话,返回 True 并且 switch 进去,否则返回 False
invisibility_of_element_located判断某个元素中是否不存在于dom树或不可见
element_to_be_clickable判断某个元素中是否可见并且可点击
staleness_of等某个元素从 dom 树中移除,注意,这个方法也是返回 True或 False
element_to_be_selected判断某个元素是否被选中了,一般用在下拉列表
element_selection_state_to_be判断某个元素的选中状态是否符合预期
element_located_selection_state_to_be跟上面的方法作用一样,只是上面的方法传入定位到的 element,而这个方法传入 locator
alert_is_present判断页面上是否存在 alert

代码示意

 

'''
等待元素出现
利用WebDriverWait 和until
until的参数为自定义方法和expected_conditions方法
'''
from appium import webdriver
from appium.webdriver.common.appiumby import AppiumBy
import time
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.actions import interaction
from selenium.webdriver.common.actions.action_builder import ActionBuilder
from selenium.webdriver.common.actions.pointer_input import PointerInput
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as ec


caps = {}
caps["platformName"] = "Android"
caps["appium:platfformVersion"] = "11"
caps["appium:deviceName"] = "OFYDHUCIPN8PHEBI"
caps["appium:appPackage"] = "com.mymoney"
caps["appium:appActivity"] = "com.mymoney.biz.main.v12.MainActivityV12"
caps["appium:noReset"] = True
caps["appium:noSign"] = True
caps["appium:unicodeKeyboard"] = True
caps["appium:resetKeyboard"] = True
caps["appium:ensureWebviewsHavePages"] = True
caps["appium:nativeWebScreenshot"] = True
caps["appium:newCommandTimeout"] = 3600
caps["appium:connectHardwareKeyboard"] = True

driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", caps)

#定义WebDriverWait对象,设置等待的时间
wait_driver = WebDriverWait(driver,20)


#点击记一笔按钮
add_trans_btn = driver.find_element(AppiumBy.ID,"com.mymoney:id/add_trans_btn") 
print("add_trans_btn 的文本是,",add_trans_btn.text)
add_trans_btn.click()

#用自定义方法判断元素是否出现
wait_driver.until(lambda lam1: driver.find_element(AppiumBy.ID,"com.mymoney:id/cost_btn"),"com.mymoney:id/cost_btn 没定位到")
#借助expected_conditions的方法定位元素是否出现
wait_driver.until(ec.presence_of_element_located((AppiumBy.ID,"com.mymoney:id/cost_btn")),"com.mymoney:id/cost_btn 元素找不到")

#presence_of_element_located参数要注意,它只能传一个参数,所以我们参数是传的一个元祖,需要两个小括号
cost_btn = driver.find_element(AppiumBy.ID,"com.mymoney:id/cost_btn")
#向文本框中输入数字
print("输入框中的文本是",cost_btn.text)

总结:

等待元素方法使用建议是根据APP的相应情况使用显示等到,实际应用中可以将是否等到元素出现封装,以便在测试用例中方便使用。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐