测试人社区

关于显示等待和隐式等待的理解

以下是我之前固有思维中对隐式等待和显示等待区别的理解:

隐式等待需要等待整个页面加载完,才会去找整个dom树中找元素,即页面加载完后,代码块执行到需要定位的元素时,这个时候会去整个dom树中找该元素,如果在规定时间内找到了,那么立刻执行下一句代码,如果没找到,会不断的轮巡dom树,直到超过设定的等待时间。
但是当页面中的需要动态加载的内容很多时,有时候需要的元素其实早已经找到了,但还是得等这个页面加载完,才会去执行下一步,这个时候只用隐式等待就不高效了,而且有些元素不一定能找的到。

那么就轮到显示等待登场了,显示等待不会等页面加载完,它会在页面加载的同时,就开始以你设定的频率去不断的找元素,只要找到元素并且满足设定的条件,直接执行下一步,不会过多的等待,显示等待会高效很多。

所以,综上所述,在实际项目中,最佳方案是隐式等待全局控制,其他所有元素查找都尽量用显示等待,这样显示+隐式等待双保险,能极大提升脚本的稳定性和效率。

最近听了老师的课程后,发现好像有些地方是不是理解错了:

1、隐式等待是否也不需要等待整个dom树加载完才开始找元素,而是在加载页面的同时就已经开始在找元素了呢?
2、设置显示等待的原因,是因为隐式等待设置的时间是固定的,而要找的每个元素等待时间或短或长,所以用隐式还不够智能?
3、在项目中是否每个元素定位都用显示等待更好呢?

麻烦老师看到能解惑一下(不好意思,可能废话有点多)

1 Like

1.根据WebDriver官网对于 Implicit wait timeout的介绍,隐式等待相当于在WebDriver级别的显式等待,也是相同的策略,使用元素定位进行多次重复查找,一旦找到就返回结果。

2.有两种可能需要显式等待:

  • 因为隐式等待一旦找到就会返回结果,而返回结果到脚本,再接收到下一条操作刚才找到的元素的命令需要一段时间。这段时间可能页面已经因为加载后续内容而发生了变化,之前找到的元素也受到了影响,于是操作元素的命令就无法正常执行了。
  • 因为隐式等待只要能定位到元素就会返回,并不能对元素的各种状态进行判断,所以显式等待中丰富的元素属性判断就为有特殊定位需求的情况提供了解决方案。

3.通常的建议当需要等待时尽量使用显式等待,如果需要隐式等待的话局部使用局部设置,使用完毕复位。不是很推荐隐式等待和显式等待混合使用,详见 Selenium大佬对于不应该混用的解释

以上是一点个人见解,希望能有帮助

那问题来了,什么时候适合用隐式等待。。这么一说,感觉所有元素定位都用显示等待就好了,速度还快,但是在实际工作项目中也遇到过不稳定的情况,不知道是什么原因(可能是隐式显示混合用了?)

本质是在最大超时时间内循环检测,默认0.5s,检测的方式在web下是执行js,app下是调用uiautomator,所以就算没有全部渲染,也是可以检测的。很多页面都是动态加载的,这期间的每个时刻dom都是完整的,只是在不断改变控件树而已。

隐式等待解决的是找控件的问题,但是等待控件消失这个就乏力了,不是做不到,而是做起来非常麻烦,所以显式等待机制就需要了。要等待的条件可以非常丰富,不再局限于简单的查找。

假设有个控件等待60s才能找到,如果用隐式等待那么其他用例也会在找不到控件的时候进行60s等待,总体用例时间会增加很多的。这也是要针对性的使用显式等待的原因。

一般默认全局隐式等待,时间比较短,不然会导致整体用例时间增长。显式等待用于剩下的所有需要等待的情况。理论上点击一个控件之前需要等待可点击的,这个需要自己封装,会让执行更稳定的。最新版本的课程里,我们就是这样教的。

有些场景下,就算可点击也是点击了没有效果的,需要用到循环点击显式等待下个控件出现这种技巧。

所以我多次提到做自动化,如果直接用原生api而不是自己封装框架,那么稳定性是很差的。

老师,我这样封装的行吗?

def wait_element(driver, timeout,poll,locator):
    """

    :param driver: 浏览器驱动
    :param timeout:超时时间
    :param poll:频率,比如0.2,即每隔0.2秒查找一次
    :param locator:元素定位器,是个元组
    :return:
    """
    used_time = 0
    while used_time < timeout:
        try:
            elem = driver.find_element(*locator)
            return elem
        except:
            time.sleep(poll)
            used_time += poll
    # 等待超时后报错
    raise TimeoutError("等待超时")

你先看下显式等待的源代码吧,写的比你的好。。。
直接用即可,封装的是点击行为,而不是单个的等待。

噢噢,理解错了,意思是封装的是点击、输入等这些操作步骤,就是上课老师讲的步骤的数据驱动?

所以隐式等待是加载页面的同时就开始查找元素了。这样的话,会不会有这种情况,页面尚未加载完成,隐式等待就已经超时?