☰
Selenium Web自动化测试实战:环境搭建、元素定位与工程避坑
2026/10/14 22:55:03 网站建设 项目流程

1. Selenium的本质:不止是自动化测试工具

1.1 我眼中的Selenium到底是什么

很多刚入行的测试工程师听到“Selenium”这个词,第一反应是“哦,那个做Web自动化测试的工具”。这个说法没错,但太窄了。我做了这么多年自动化,越来越觉得Selenium更像是一座连接浏览器和代码的桥梁——它让你用Python、Java、C#这类编程语言,精准地操控Chrome、Firefox、Edge这些浏览器,像真实用户一样去点击、输入、跳转、断言。

你不需要知道浏览器底层是怎么渲染页面、怎么处理JavaScript的,Selenium WebDriver把这一切细节都封装好了。你只需要告诉它:“打开这个网址”、“找到那个输入框”、“输入这串文字”、“点击这个按钮”,它就能按指令执行。这种“按指令办事”的特性,让它特别适合做三件事:Web自动化测试、跨浏览器兼容性验证、还有各类网页数据采集任务。

我见过很多团队踩过一个坑——一开始想自己封装一套浏览器自动化框架,结果开发者写了几个月还是到处报错。其实Selenium作为成熟的开源方案,生态完整、社区庞大、文档丰富,直接把精力花在解决业务问题上才是明智选择。

1.2 一个类比帮你彻底搞懂运行原理

为了把底层逻辑讲清楚,我得用一个生活化比喻。把Selenium想象成一个“不会开车但会看路牌的乘客”,浏览器就是“出租车司机”。

  • 乘客通过Selenium的接口发出指令:“我要去某个URL”
  • 出租车司机(浏览器)负责实际行驶:加载页面、执行JavaScript、渲染DOM
  • 乘客手上有一份地图(DOM树),能实时看到自己“开到哪里”—也就是当前页面有哪些元素可以操作

WebDriver协议就是这个“乘客和司机之间的沟通语言”。它是一套标准化的HTTP接口,由浏览器驱动程序(ChromeDriver、GeckoDriver等)负责翻译执行。这就解释了为什么每次用Selenium前都要装对应的驱动——没有司机,你说什么浏览器都听不懂。

1.3 为什么在2025年我依然推荐学Selenium

这些年冒出了很多新工具,像Playwright、Cypress,各有各的优势,但Selenium的地位依然稳固。原因很实在:

  • 语言支持广:Python、Java、C#、Ruby、JavaScript都支持,团队用什么语言都能接入,不像某些工具被语言绑定死。
  • 浏览器覆盖全:Chrome、Edge、Firefox、Safari全覆盖,主流的浏览器驱动一直都在更新,没有掉队。
  • 社区积累深:遇到问题基本都能搜到答案,各种疑难杂症前人早就踩过坑并整理成了方案。
  • 生态兼容好:能轻松集成到Pytest、JUnit、TestNG这些测试框架里,再配合Allure、ExtentReport做报告,搭建一套完整的自动化测试体系很方便。

当然,这不是说Selenium就是无敌的,它也有缺点,比如对iframe、弹窗、Shadow DOM这些特殊场景的处理比较繁琐,执行速度相对较慢。但这些痛点都有对应的解决套路,我在后面的章节会逐一展开。

2. 零基础环境搭建:从安装到跑通第一个脚本

2.1 环境准备清单

开工前得把工具备齐。以下是我推荐的组合装:

  • Python 3.8以上(推荐3.10或3.11,兼容性最好)
  • 最新版Google Chrome浏览器
  • 对应版本的ChromeDriver驱动
  • Selenium库(pip安装)
  • 一个支持语法高亮的编辑器(VS Code或PyCharm都行)

有人喜欢用Selenium IDE这个浏览器插件写脚本,我个人的建议是:了解一下可以,但别依赖它。IDE更适合快速录制页面操作流程、生成初步脚本,但生成出来的代码通常比较冗余,可维护性也差。真要投入项目使用,还是手工写代码更靠谱。

2.2 驱动配置的那些坑

理论上,Selenium会自动查找浏览器对应的驱动,但实际项目里经常需要我们手动指定驱动路径。我拿ChromeDriver举例,第一步是确认浏览器版本。打开Chrome,在地址栏输入chrome://version,看到版本号后,去对应的驱动下载地址找到一致的大版本号下载。

为什么强调“大版本号”?因为Chrome和ChromeDriver的版本必须保持主版本一致,比如浏览器是128.0.xxx,驱动就得是128.0.yyy,小版本不一致一般没事,但要小心主版本不对直接报SessionNotCreatedException。

下载完成后,Windows系统建议把chromedriver.exe放在一个固定目录,比如D:\tools\chromedriver\,然后在代码中显式声明路径:

from selenium import webdriver # 方式一:指定驱动路径 driver = webdriver.Chrome(executable_path=r"D:\tools\chromedriver\chromedriver.exe") # 方式二(推荐):新版Selenium直接写路径 from selenium.webdriver.chrome.service import Service service = Service(r"D:\tools\chromedriver\chromedriver.exe") driver = webdriver.Chrome(service=service)

注意:Selenium 4.6以上版本推出了Selenium Manager,它会自动下载匹配的驱动,理论上不用再手动处理。但实际在中国网络环境下,自动下载经常失败,所以手动配置驱动仍是我心中最稳妥的方案。

2.3 第一个脚本:验证环境是否打通

环境配好后,跑一个最简单的脚本试试水,脚本逻辑就是打开一个网页,然后打印页面标题。

from selenium import webdriver from selenium.webdriver.chrome.service import Service import time service = Service(r"D:\tools\chromedriver\chromedriver.exe") driver = webdriver.Chrome(service=service) driver.get("https://www.baidu.com") time.sleep(2) print(driver.title) driver.quit()

如果控制台能正常打印出页面的title,说明整个链路已经打通了。这时候我建议你顺手做两件事,一是把driver.quit()养成肌肉记忆,不管脚本成功失败都要关闭浏览器,否则大量残留的chromedriver进程会吃光内存;二是学会设置浏览器下载目录和用户目录,后面做爬虫或者处理文件下载时会频繁用到。

有一点我得反复提醒:如果你看到类似“executable_path has been deprecated, please pass in a Service object”的警告,说明你用的Selenium版本比较新,需要改用Service方式,别直接忽略警告,否则升级版本后脚本会直接报错。

3. 元素定位:自动化脚本的核心命脉

3.1 八种定位方式的适用场景

自动化操作的一切基础,都得先找到页面上的元素。Selenium提供了八种定位手段,我用一张表整理一下各自的适用场景:

定位方式语法示例适用场景优先级
idfind_element(By.ID, "login-btn")页面中id唯一时首选
namefind_element(By.NAME, "username")表单元素常用高
class_namefind_element(By.CLASS_NAME, "form-item")样式类名稳定时中
tag_namefind_element(By.TAG_NAME, "input")极少单独使用,常配合其他方式低
link_textfind_element(By.LINK_TEXT, "点击注册")精准匹配超链接文本中
partial_link_textfind_element(By.PARTIAL_LINK_TEXT, "注册")模糊匹配超链接文本中
css_selectorfind_element(By.CSS_SELECTOR, "#btn-submit .btn")结构清晰、性能好高
xpathfind_element(By.XPATH, "//button[contains(text(),'登录')]")无法用CSS时兜底中

我的选型原则很简单:有id优先用id,其次看name,再其次想CSS Selector,XPath尽量放最后。原因是id和name在绝大多数情况下是唯一的,定位稳定且可读性好;CSS Selector的解析效率比XPath高,而且当页面结构变化时CSS通常还能扛住;XPath虽然功能强大、可以沿着文档树任意查找,但定位路径太长时性能较差,页面结构一调整就全盘崩溃。

3.2 动态页面与等待机制的深度理解

动态页面是自动化脚本最容易踩雷的区域。很多页面加载完HTML后就立刻发起异步请求更新数据,Selenium默认的查找时机可能早于数据回来,导致“元素不存在”的假象。这时候就需要等待机制出场了。

Selenium有两种等待方式:

隐式等待,全局生效,告诉WebDriver在查找元素时最多等待多少时间。比如driver.implicitly_wait(10),意味着10秒内不断重试查找,直到找到元素或超时。适用场景是页面整体加载比较稳定的情况,但遇到局部异步加载就会显得笨拙。

显式等待,针对特定元素设置等待条件和超时时间:

from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By # 等待“登录按钮”变得可点击,最多等15秒 login_btn = WebDriverWait(driver, 15).until( EC.element_to_be_clickable((By.ID, "login-btn")) ) login_btn.click()

显式等待的表达能力远超隐式等待,EC模块里封装了很多现成的条件,比如元素可见、存在、包含文本、属性变化等等。我在项目里80%的等待都靠显式等待搞定,隐式等待只作为兜底保险。

注意:不要把隐式等待当成万能良药。过度依赖隐式等待会让脚本整体变慢,尤其是当某个元素确实缺失时,每个定位调用都要白白等满10秒,多级页面叠加起来性能损失非常明显。而且隐式等待管不到DOM元素的“可见性”和“可点击性”,隐藏元素照样能被找到,但点击时就会异常。

3.3 常见交互操作:点击、输入与特殊键

定位到元素之后,最常用的操作无非三种:点击、输入、取值。

# 输入文字 element.send_keys("测试账号") # 清空再输入(特别容易忽略!) element.clear() element.send_keys("新账号") # 点击按钮 button.click() # 获取元素文本 text = element.text # 获取属性值 href = element.get_attribute("href")

有个小细节值得单独拿出来说:很多人在动态页面上输入文字时,发现有时候send_keys没生效,其实是因为输入框里已经有默认值,而代码直接追加到后面了。最稳妥的做法是先clear()再send_keys(),如果clear()还不行,那就用键盘快捷键全选再输入:

from selenium.webdriver.common.keys import Keys element.send_keys(Keys.CONTROL, "a") element.send_keys("新内容")

处理键盘操作时还要记得,Enter、Tab、Esc这些都有对应的Keys枚举值。有些场景下,用send_keys(Keys.ENTER)比直接点击按钮更稳,比如搜索输入框在输入后需要触发联想更新时。

4. 从需求到实现:一个完整的自动化登录流程

4.1 场景分析

理论说了一大堆,还是得拿一个实际场景串一遍。假设我们要对一个管理后台系统做自动化登录,页面结构大致是:用户名输入框、密码输入框、登录按钮,点击登录后跳转到首页并显示用户名。这个场景在几乎所有后台系统上都能复现,非常适合作为练手项目。

先别急着写代码,想一想这个场景里的关键点:

  • 登录成功后页面会跳转,但跳转需要时间,必须用等待机制
  • 登录失败时会弹出错误提示,如何捕获并区分成功与失败
  • 如果用户名密码固定写死,后面维护成本高,得考虑参数化
  • 脚本结束时要给出明确的结果断言,而不是只“跑了一遍”

4.2 完整代码实现

结合前面讲的内容,写一个带封装的登录流程脚本:

from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.chrome.service import Service from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC class LoginPage: def __init__(self, driver): self.driver = driver self.username_input = (By.ID, "username") self.password_input = (By.ID, "password") self.login_button = (By.ID, "login-btn") self.success_text = (By.CSS_SELECTOR, ".user-info .name") def input_username(self, username): WebDriverWait(self.driver, 10).until( EC.visibility_of_element_located(self.username_input) ).send_keys(username) def input_password(self, password): WebDriverWait(self.driver, 10).until( EC.visibility_of_element_located(self.password_input) ).send_keys(password) def click_login(self): WebDriverWait(self.driver, 10).until( EC.element_to_be_clickable(self.login_button) ).click() def get_success_text(self): return WebDriverWait(self.driver, 15).until( EC.visibility_of_element_located(self.success_text) ).text def test_admin_login(): service = Service(r"D:\tools\chromedriver\chromedriver.exe") driver = webdriver.Chrome(service=service) try: driver.get("https://example-admin-site.com/login") login_page = LoginPage(driver) login_page.input_username("testuser") login_page.input_password("123456") login_page.click_login() username = login_page.get_success_text() assert username == "testuser", f"登录后显示的用户名不一致,实际为{username}" print("登录测试通过,页面显示的用户名为:", username) finally: driver.quit() if __name__ == "__main__": test_admin_login()

这个脚本里体现了几个我在实际项目中的习惯:

第一,把元素定位器和操作逻辑分离。以后页面结构调整了,只需要修改定位器那一行,别的代码都不用动。

第二,用finally保证浏览器一定会关闭。脚本出异常时如果不做处理,Chrome会留下一堆僵尸进程,看任务管理器时乱七八糟的。

第三,对成功结果做了断言。自动化测试的价值在于“能自动判断对错”,而不是“能自动操作”。如果一个脚本只跑不查,跑完还得人来盯结果,那自动化的意义就打了大折扣。

4.3 如何应对登录过程中的验证码

真实项目里登录流程往往没有这么顺滑,最常见的就是验证码。

自动化处理验证码的方案有很多,但我的建议是先看业务方口风。如果验证码只是登录入口的安全手段,可以在测试环境申请“万能验证码”,或者把验证码校验暂时屏蔽掉。如果是对接第三方平台的验证码服务,那就得用OCR识别或者对接打码平台。

对于简单的图片验证码,可以用图像识别的方式,比如截取验证码图片,用开源的OCR模型识别文字,但不稳定的因素很多(字体变形、干扰线、背景杂色都会影响准确率)。项目中有一次识别率不到60%,最后跟开发协商加了测试白名单跳过验证码,反而省了不少力。自动化测试本来就不应该和验证码死磕,绕过去才是聪明的做法。

4.4 数据驱动设计的初步意识

写固定账号密码的脚本能跑,但效果有限。稍微进阶一点的做法是数据驱动,把测试数据从代码中剥离出来:

import csv def read_test_data(file_path): test_cases = [] with open(file_path, "r", encoding="utf-8") as f: reader = csv.DictReader(f) for row in reader: test_cases.append({ "username": row["username"], "password": row["password"], "expected": row["expected"] }) return test_cases # 遍历测试数据执行用例 for case in read_test_data("login_test_data.csv"): run_login_case(case["username"], case["password"], case["expected"])

这样就把“一组输入、一个预期结果”变成数据条目,新增用例时不需要改代码,只要在CSV里加一行就行。多浏览器兼容测试也可以用同样的思路:把浏览器类型作为参数,循环跑Chrome、Firefox、Edge。

5. 常见问题排查与实战避坑指南

5.1 元素定位失败的四大原因

自动化脚本跑到一半突然报“NoSuchElementException”,这大概是我被问次数最多的问题了。根据我多年的排查经验,原因基本就集中在下面几个:

原因一:页面没加载完就找了。这是最常见的一种,解决办法是加显式等待,等待目标元素出现后再操作。

原因二:元素在iframe里。页面里嵌着iframe时,主文档里根本找不到iframe内部的元素。必须先切换到iframe里再去定位:

# 切换到 iframe driver.switch_to.frame("iframe_name_or_id") # 操作完切回主文档 driver.switch_to.default_content()

这里最容易翻车的是:进入iframe后如果还要操作主文档里的元素,必须记得切回去,否则就会报找不到元素。

原因三:元素属性是动态的。有些前端框架的id和class是运行时时生成的,比如id="input-12345-abc",每次刷新都变。遇到这种情况,千万别硬编码动态属性,改用相对稳定的父节点定位:

  • 用CSS的contains匹配属性片段
  • 用XPath的contains函数模糊匹配
  • 通过邻近元素的相对位置定位

原因四:元素被遮挡导致无法点击。按钮就在那里,DOM里也存在,但被浮层或弹窗挡住了。WebDriver报“ElementClickInterceptedException”。解决思路是等遮挡元素消失,或者用JavaScript强制执行点击:

from selenium.webdriver.common.by import By element = driver.find_element(By.ID, "submit-btn") driver.execute_script("arguments[0].click();", element)

这个办法能绕过透明遮罩层的拦截,但只作为应急手段,正常研发流程中还是应该推动开发修掉遮挡问题。

5.2 同步超时与执行缓慢问题

自动化脚本最怕的就是“时而能跑过,时而过不了”,这种不稳定比完全跑不通更折磨人。根据我长期观察,这种问题绝大多数和等待策略有关。

一个页面如果包含多个异步请求,不同接口返回的速度差异很大,统一用一个固定sleep时间是完全错误的做法。sleep时间设长了,整个脚本跑得很慢;设短了,某些网络状况下就会失败。更合理的方案是:按元素维度设置不同的显式等待,并且配合轮询机制。

class CustomCondition: def __init__(self, expected_text): self.expected_text = expected_text def __call__(self, driver): element = driver.find_element(By.ID, "load-status") return element.text == self.expected_text # 等待某个自定义条件成立,最多20秒 WebDriverWait(driver, 20).until(CustomCondition("加载完成"))

另外,我踩过一个大坑是XPath表达式写得太复杂导致定位极慢。有一次在页面上用了一个多层级XPath,每次定位要等好几秒,500条测试用例跑下来,光定位时间就占了三分之一。后来把XPath改成先按id定位父节点,再用相对路径找子节点,速度提升显著。

5.3 处理弹窗与多窗口切换

弹窗处理是Web自动化绕不开的关卡。Selenium里的弹窗分两种:一种是浏览器原生的alert弹窗,另一种是前端自定义的模拟弹窗。处理方式完全不同。

原生弹窗用switch_to.alert来处理:

# 获取弹窗 alert = driver.switch_to.alert # 获取弹窗文本 text = alert.text # 点击确定 alert.accept() # 点击取消 alert.dismiss() # 输入文本(prompt弹窗) alert.send_keys("输入内容")

模拟弹窗的本质就是一个div元素,直接定位里面的按钮点击就行,但它往往是异步出现的,必须配合显式等待。有些模拟弹窗还带淡入动画,元素DOM出现不等于可以点击,需要等待动画结束。

多窗口切换则是另一种常见场景。点击一个链接打开了新标签页,如果继续操作新页面内容,需要切换窗口句柄:

# 获取所有窗口句柄 handles = driver.window_handles # 切换到最新的窗口 driver.switch_to.window(handles[-1]) # 操作完后关闭新窗口并切回原来的 driver.close() driver.switch_to.window(handles[0])

5.4 一份高频问题速查表

最后把我常遇到的典型问题整理成表格,方便读者“对号入座”:

报错信息根本原因解决方案
NoSuchElementException元素未找到检查定位器是否正确、是否在iframe中、是否等待不足
ElementNotInteractableException元素不可交互元素隐藏或被遮罩,等条件就绪再操作
ElementClickInterceptedException点击被拦截等待遮罩消失或用JS强制点击
SessionNotCreatedException驱动版本不匹配检查浏览器和驱动的版本号是否一致
TimeoutException等待超时分析等待条件是否合理、网络状况是否过差
StaleElementReferenceException元素已过期页面刷新后需重新定位,不能沿用旧元素引用
InvalidArgumentException参数类型错误检查传入的参数值是否符合接口要求
WebDriverException通用异常优先看驱动日志定位问题

6. 进阶方向:从脚本到测试框架

6.1 为什么要从单脚本走向框架

单独一个脚本跑起来了,并不等于自动化就走通了。现实中的测试项目对自动化有更多要求:测试报告、用例管理、失败重跑、CI集成、多环境切换。这些都是单个脚本无法解决的问题。

拿失败重跑举个例子。脚本因为网络抖动挂了一条用例,重新跑一遍可能就过了。如果每次都要人去重启脚本,自动化反而变成了负担。用Pytest的插件机制可以轻松实现:

# conftest.py import pytest @pytest.mark.flaky(reruns=3, reruns_delay=2) def test_login(): # 登录用例逻辑 pass

再比如,项目中有测试环境、预发布环境,URL地址不一样,那就不能把URL硬编码在脚本里。用环境变量或者配置文件的方式,配合Pytest的fixture统一注入,脚本就能在不同环境间灵活切换。

6.2 合理使用Page Object模式

前面登录示例里用了类似Page Object的结构,那只是个简易版。真正项目级的Page Object模式,核心思想是把每个页面抽象成一个独立的类,页面上的元素和对应的操作都封装在类里,测试用例只关心业务流程,不直接接触元素定位细节。这样的好处是,页面发生变化时只需要改对应的Page类,不用每个用例都去改一处。

一个规范的Page Object应该包含:

  • 页面的元素定位器(集中定义,方便修改)
  • 页面的操作行为(封装成方法)
  • 页面的结果校验(返回状态或断言结果)

我见过不少团队把Page Object做成了“元素定位器的堆砌”,类里全是find_element,逻辑却散落在各个测试函数里,这其实没有达到封装的目的。判断封装得是否好,有个朴素标准:测试用例读起来像在描述业务操作,而不是在描述WebDriver API调用。

6.3 持续集成中的接入方案

自动化脚本要真正发挥作用,必须接入持续集成流程,让每次代码提交都自动触发回归测试。以Jenkins为例,我的习惯做法是:

  • 将自动化代码托管到代码仓库,拉取固定分支
  • Jenkins配置定时构建或代码变更触发
  • 在构建步骤中执行命令行跑测试并生成报告
  • 测试结果回传到构建任务,失败时通过邮件或IM通知相关人员

关键点是要控制执行时长。如果自动化用例量很大,全部跑完要两三个小时,那就得考虑分布式执行。Selenium Grid在这一点上仍然很值得提:

# 启动Hub端 java -jar selenium-server-4.0.0.jar hub # 注册节点到Hub java -jar selenium-server-4.0.0.jar node --hub http://localhost:4444

Grid的好处是能同时调度多台机器、多个浏览器执行同一批测试,把执行时间大幅压缩。之前在某公司的项目中,用四台机器搭了一个小Grid,两百条用例的回归时间从两小时缩到了二十五分钟,性价比非常高。

6.4 Selenium与爬虫的结合思考

除了测试,Selenium在采集动态渲染网页数据方面也有独特价值。但不是所有采集任务都需要Selenium,这里我要给个理性的判断:如果目标网站的数据是通过接口返回的,用requests直接请求接口是最省资源的方式;只有在接口加密参数复杂、必须靠浏览器环境才能拿到数据的场景下,Selenium才有用武之地。

这里涉及到Selenium操作浏览器时的资源损耗问题,我想提醒一句:别用Selenium去并行开几十个浏览器采集数据,内存会直接炸掉。更好的做法是,能用API接口获取的数据就不要用浏览器渲染。

6.5 浏览器配置的头疼问题和优化方案

跑自动化时经常需要配置浏览器的参数,比如无头模式、禁用GPU、跳过证书校验等。这些参数在Selenium里通过ChromeOptions来设置:

from selenium.webdriver.chrome.options import Options options = Options() # 无头模式,不显示浏览器窗口 options.add_argument("--headless=new") # 禁用GPU加速 options.add_argument("--disable-gpu") # 解决无头模式下部分页面不渲染的问题 options.add_argument("--no-sandbox") # 跳过SSL证书校验 options.add_argument("--ignore-certificate-errors") # 设置磁盘缓存目录 options.add_argument("--disk-cache-dir=D:/temp/chrome_cache") driver = webdriver.Chrome(service=Service(r"D:\tools\chromedriver\chromedriver.exe"), options=options)

无头模式跑自动化能大幅减少资源消耗,适合CI环境下批量执行。但要注意,无头模式对某些前端展示行为模拟得不如有头模式准确,如果出现“无头模式找不到元素、有头模式正常”的情况,应优先检查是否是浏览器渲染差异导致的。

7. 值得长期坚持的几个实践习惯

自动化脚本的职业生涯里,我慢慢总结出一套自己的“做事惯例”,分享出来供参考。

第一,日志记录比打印重要。脚本运行过程中只靠print输出,排查问题时信息量远远不够。建议在关键步骤加上日志:

import logging logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s") logger = logging.getLogger(__name__) logger.info("正在输入用户名:%s", username) logger.info("点击登录按钮") logger.error("登录失败,页面提示:%s", error_msg)

有了日志后,配合持续集成里的截图留存,问题复现和定位的效率会高非常多。

第二,失败截图是刚需。一条用例跑挂了,如果没有截图,单看错误信息往往很难判断当时的页面状态。给测试框架加上自动截图逻辑:

import os import time def take_screenshot(driver, name=None): if name is None: name = time.strftime("%Y%m%d_%H%M%S") path = os.path.join("screenshots", f"{name}.png") driver.save_screenshot(path) return path

我习惯在异常捕获里调用这个函数,让每次失败都留下证据。

第三,不要为了覆盖率而堆用例。自动化用例的维护成本很高,一条用例前期编写、中期维护、后期失效修改,消耗的时间远比手工执行一次多得多。投入产出比不高的用例不如不写。我通常坚持一个原则:稳定、核心、重复性高的流程适合自动化,而复杂的探索性测试交给人工更划算。

第四,保持Selenium版本的敏感性。Selenium迭代很快,每次升级都可能导致已有的API行为变化。升级前先看Changelog,并且在升级后用全量回归验证一遍,避免“版本升级一时爽,测试跑挂火葬场”的情况。

自动化测试这件事,靠的从来不是某一项神奇的技巧,而是扎扎实实把每一步做对:环境搭好、定位选好、等待配好、异常处理好、日志留好。这些基础打牢了,不管Selenium后续怎么迭代,你迁移到任何自动化工具都不会慌张。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询