Selenium 让 Selenium 稳定运行的技巧

付海全 · 2017年02月09日 · 最后由 lyyyyyyy 回复于 2022年03月16日 · 4096 次阅读

Selenium 简介

Selenium 是非常流行的 Web 自动化测试工具。它具有自动化测试用例制作简单,支持多种浏览器和不同的操作系统等优点。

Selenium 脚本不稳定的问题

有很多时候 Selenium 的自动化测试脚本运行并不是很稳定。经常会遇到系统明明正常运行,但是测试却失败的情况。例如,点击上传图片按钮并上传图片,如果在上传加载完成之前就操作下一步,会提示错误信息。

出现问题的原因可能是服务器的响应速度慢,在页面内容没有加载完毕的状态下 Selenium 就执行了下一条命令,从而导致测试失败。上面的上传图片场景,虽然在上传图片后可以加入固定的等待几秒钟的代码,但是因为上传图片的速度并不是固定的时间,当服务器的负载较高的时候,上传图片的速度变慢,所以造成了测试的失败。

脚本运行不稳定的解决方法

  • 固定等待时间

上面的问题的解决方法之一就是使用 python 程序语言的 sleep 函数,来暂停固定秒数的时间,通过延迟执行下一条命令,多少能有所改善。但是这个方法为了解决偶尔发生的问题,不得不在测试(用例)脚本中插入很多 sleep 语句,会造成测试时间的变长,因此并不推荐。

下面是通过 python 语言来实现固定等待时间的相关代码:

import time

time.sleep(2) #默认等待2秒
  • 设置隐性等待时间

可以通过下面代码来设置 selenium 内置的智能等待时间,但是在上传图片等待的情况下智能等待没有生效。

from selenium import webdriver   #导入浏览器驱动

browser = webdriver.Chrome("/home/kyle/bin/chromedriver")
browser.implicitly_wait(10)  #设置智能等待10秒
  • 使用 selenium 提供的 WebDriverWait 方法

通过下面代码可以使用 selenium 提供的等待页面元素加载的方法:

from selenium.webdriver.support.wait import WebDriverWait

# 使用selenium提供的WebDriverWait方法,每0.5秒检查一次定位的元素,超时设置是2秒
WebDriverWait(browser, 2).until(
        lambda driver: driver.find_element_by_tag_name('body'))
  • 更好的解决方法

通过利用 python 的异常捕获机制和循环语句,使程序在一定时间内即使 selenium 执行命令失败,也会继续重复执行同一条命令多次,直到成功为止。
下面是相关的 python 程序代码:

import time
from selenium import webdriver   #导入浏览器驱动

def smart_wait(self, element_id):  # 智能等待时间,60秒超时
    for i in range(60):            # 循环60次,从0至59
        if i >= 59 :               # 当i大于等于59时,打印提示时间超时
            print("timeout")    
            break
        try:                       # try代码块中出现找不到特定元素的异常会执行except中的代码
            if browser.find_element_by_id(element_id): # 如果能查找到特定的元素id就提前退出循环
                break
        except:                    # 上面try代码块中出现异常,except中的代码会执行打印提示会继续尝试查找特定的元素id
            print("wait for find element")
        time.sleep(1)

实例说明

在实际测试工作中,有上传图片的场景,上传图片的时间和服务器的响应时间以及客户端网络状况有关系,所以有时候速度慢,有时候速度快。这种情况不适合使用固定等待时间的解决方法。可以通过上面提到的第二种方案来处理,先通过下面代码开始上传图片。

browser.find_element_by_id(button_id).find_element_by_name("file").send_keys(file_path)
# 注意:上面语句中find_element_by_id(button_id)中button_id为上传图片按钮的元素id

然后调用上面提到的 smart_wait(check_id) 函数,传入参数要查找的元素 id,这个参数的 id 是下面截图中红框标记处的 id。找到这个元素 id 证明上传图片已经成功,可以开始下一步操作,如果找不到这个元素 id 说明上传图片还没有完成,还需要继续等待上传完成。

如果 selenium 能找到这个元素 id 证明上传已经完成,会提前退出循环,继续执行下一步代码语句。如果找不到这个元素 id 就等待 1 秒之后继续查找,在默认的 60 次循环内直到找到为止。如果直到最后一次循环都没有找到想要的元素就打印提示信息:“timeout”。

参考文献:

《高效团队开发工具与方法》池田尚史,藤仓和明,井上史彰 著

共收到 10 条回复 时间 点赞

可以加一个 smart find ?

我前段时间也在做 Selenium 自动化测试,对于这类问题的解决方法是使用 WebDriverWait。常用下面几种:

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as ec

# sec为等待时间
try:
    WebDriverWait(browser, sec).until(
        # 等待XPATH元素可见
        ec.visibility_of_element_located((By.XPATH, xpath))
        # 等待XPATH元素不可见
        ec.invisibility_of_element_located((By.XPATH, xpath))
        # 等待XPATH元素展现
        ec.presence_of_element_located((By.XPATH, xpath))
        # 等待标题为title
        ec.title_is(title)
    )
except Exception as e:
    logging.warning(e)
    sys.exit(-1)

具体可以看这里:http://selenium-python.readthedocs.io/waits.html

与开发合作源码里为元素加 debug_id,大量使用 byid,减少 byxpath 使用,可以缓解一大半的问题

隐式等待一般不要乱用,弊端多。个人感觉影响 UI 自动化稳定性因素太多了,要实现长期趋于稳定的用例集,得下很多功夫。

#1 楼 @Lihuazhang 请问 smart find 是什么方法?没有用过

#5 楼 @kylekaka 就是把 smart wait 集成到 find 里面去

我也用类似方法

很实用的方法

—— 来自 TesterHome 官方 安卓客户端

恕我愚昧,这个 smart wait 和显示等待有啥区别吗?

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册