找回密码
 立即注册
首页 业界区 科技 【软件测试】等待的艺术:详解显式等待与隐式等待,告别 ...

【软件测试】等待的艺术:详解显式等待与隐式等待,告别time.sleep!

幌斛者 5 天前
各位测试同仁,你是否还在为自动化测试脚本中的各种“元素未找到”、“交互失败”而头疼?是否在你的脚本里随处可见 time.sleep(10) 这样的“魔法数字”?
今天,我们就来深入探讨Selenium等待机制的核心艺术,彻底抛弃低效的 time.sleep(),让你的自动化脚本变得更健壮、更快速、更专业!
 

一、为什么单纯的 time.sleep() 是万恶之源?

在我们深入正题前,先来声讨一下这个看似“好用”的 time.sleep()。
  1. import timefrom selenium import webdriverdriver = webdriver.Chrome()driver.get("https://example.com")# 糟糕的实践:固定等待10秒time.sleep(10)element = driver.find_element("id", "slow-loading-button")element.click() 
复制代码
它的三大罪状:

  • 效率低下:无论页面加载快慢,都必须死等固定的时间。如果元素提前加载好了,剩下的时间就白白浪费;如果网络慢,10秒后元素还没出来,脚本依然会报错。
  • 不稳定:网络速度、服务器负载、客户端性能都会影响元素的加载时间,一个固定的等待时间无法适应这些变化。
  • 难以维护:脚本里充斥着大量的 sleep,代码变得臃肿且可读性差。
结论:time.sleep() 可以作为调试的临时手段,但绝不应出现在正式的自动化脚本中。
二、Selenium等待机制的“双雄”:隐式等待 vs. 显式等待

Selenium提供了两种智能的等待方式来解决异步加载的问题,它们各司其职,用法迥异。
1. 隐式等待 (Implicit Wait)

隐式等待像一个全局性的设置。它告诉WebDriver在查找任何一个元素时,如果立即找不到,就等待一段固定的时间,直到元素出现或者超时。

  • 作用范围:针对整个WebDriver生命周期中的所有 find_element 操作。
  • 设置方法:一次性设置,全局生效。
  • 行为:轮询查找元素,一旦找到就立即返回,不会等到超时。
  1. from selenium import webdriverdriver = webdriver.Chrome()# 设置隐式等待时间为10秒driver.implicitly_wait(10)driver.get("https://example.com")# 这四条查找语句都会受到上面隐式等待的约束element1 = driver.find_element("id", "fast-element")    # 可能只等1秒就找到了element2 = driver.find_element("name", "slow-element")  # 最多会等10秒element3 = driver.find_element("class name", "another-element")element4 = driver.find_element("tag name", "some-tag")
复制代码
优点:设置简单,一劳永逸。
缺点:不够灵活,只能用于元素是否存在,无法处理更复杂的条件(如元素可点击、可见等)。
2. 显式等待 (Explicit Wait)

显式等待则像一个精准的狙击手。它针对某个特定的元素和条件,设置一个最大的等待时间。在等待期内,WebDriver会不断地检查条件是否满足,一旦满足就立即继续执行,否则在超时后抛出异常。
它的核心是 WebDriverWait 类和 expected_conditions 模块。

  • 作用范围:针对某个特定的条件和元素。
  • 设置方法:在需要的地方临时设置,精确控制。
  • 行为:轮询检查预期条件,条件成立则返回结果。
基本语法:
  1. from selenium.webdriver.support.ui import WebDriverWaitfrom selenium.webdriver.support import expected_conditions as ECfrom selenium.webdriver.common.by import By# 创建一个WebDriverWait实例,设置最大等待时间10秒wait = WebDriverWait(driver, 10)# 用法:until方法配合expected_conditionselement = wait.until(    EC.presence_of_element_located((By.ID, "myDynamicElement")))
复制代码
expected_conditions 常用条件(EC):
| 条件方法 | 描述 |
| :--- | :--- |
|presence_of_element_located| 元素出现在DOM中(不一定可见) |
|visibility_of_element_located| 元素不仅出现,还可见|
|element_to_be_clickable| 元素是可见且可被点击的(用于点击操作前) |
|text_to_be_present_in_element| 元素中包含特定的文本 |
|alert_is_present | 出现Alert弹窗 |
实战示例:等待一个可点击的按钮
  1. from selenium import webdriverfrom selenium.webdriver.common.by import Byfrom selenium.webdriver.support.ui import WebDriverWaitfrom selenium.webdriver.support import expected_conditions as ECdriver = webdriver.Chrome()driver.get("https://example.com/login")try:    # 等待最多15秒,直到登录按钮可点击    login_button = WebDriverWait(driver, 15).until(        EC.element_to_be_clickable((By.CSS_SELECTOR, "button[type='submit']"))    )    login_button.click()    print("成功点击登录按钮!")except TimeoutException:    print("登录按钮在15秒内仍未变得可点击!")    # 这里可以加入截图或日志记录,便于调试    driver.save_screenshot('login_timeout.png')
复制代码
优点:极其灵活、强大、高效。可以应对任何复杂的异步场景。
缺点:代码量稍多,需要在多个地方编写。


三、最佳实践与“双雄”混用指南

1. 不要混合使用!
这是一个非常重要的坑!同时设置隐式等待和显式等待会导致不可预测的等待时间。
例如:

  • 隐式等待 = 10秒
  • 显式等待 = 15秒
    那么,在显式等待的条件检查中,如果找不到元素,它可能会先触发10秒的隐式等待,然后再进行自己的15秒轮询检查,导致实际等待时间达到 25秒!这很容易让人困惑。
2. 推荐的策略:

  • 完全禁用隐式等待:driver.implicitly_wait(0)
  • 全程使用显式等待:在所有需要与动态元素交互的地方,使用 WebDriverWait 和 EC。这是目前公认的最可靠、最专业的做法。
  • 设置一个合理的全局默认等待时间:可以在框架层面封装一个自己的 wait 对象,统一设置超时时间。
  1. # 最佳实践示例driver = webdriver.Chrome()driver.implicitly_wait(0)  # 禁用隐式等待# 封装一个默认的wait对象def get_wait(driver, timeout=30):    return WebDriverWait(driver, timeout)wait = get_wait(driver)# 然后在任何地方都使用这个wait对象wait.until(EC.visibility_of_element_located((By.ID, "content"))).click()
复制代码
 

四、总结与对比表

| 特性 | 隐式等待 (Implicit)|显式等待 (Explicit)|time.sleep()|
| :--- | :--- | :--- | :--- |
| ** scope ** | 全局,所有find_element| 局部,针对特定条件 | 全局,死等 |
|灵活性| 低 |极高| 无 |
|效率| 中 |高| 极低 |
|可维护性| 中 |高| 低 |
|推荐度| ⭐⭐ |⭐⭐⭐⭐⭐|绝不推荐 |
最终建议:
告别 time.sleep,忘掉隐式等待,将显式等待作为你的唯一标准。 这小小的改变,将是你的Web自动化脚本从“玩具”走向“工程”的关键一步。
本文原创于【程序员二黑】公众号,转载请注明出处!
欢迎大家关注笔者的公众号:程序员二黑,专注于软件测试干活分享,全套测试资源可免费分享!
最后如果你想学习软件测试,欢迎加入笔者的交流群:785128166,里面会有很多资源和大佬答疑解惑,我们一起交流一起学习!

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册