1. 为什么你需要Selenium自动化测试?
每次手动点击网页按钮时,你有没有想过让程序自动完成这些重复操作?去年我接手一个电商项目,每天要手动测试30多个页面的优惠券功能,直到发现Selenium这个神器。它就像个不知疲倦的机器人,能24小时自动帮你点击、输入、验证页面,特别适合下面这些场景:
- 凌晨3点的定时巡检:设置脚本自动检查登录页是否正常,再也不用半夜被报警电话吵醒
- 注册流程的50次重复验证:新用户从填写到提交的全流程,手动测试要1小时,自动化只要3分钟
- 浏览器兼容性地狱:同样的操作在Chrome/Firefox/Edge上表现是否一致?一键跑完所有测试
但要注意,不是所有情况都适合自动化。上周有个团队想用Selenium测试频繁改版的首页,结果每天都要重写脚本,这就是典型的反面案例。最适合的场景是核心业务流程(如支付、登录)和长期稳定的功能模块。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 5分钟快速搭建测试环境
新手最怕环境配置,我用Windows/Mac双系统实测的这个方案成功率最高:
bash复制# 1. 安装Python(推荐3.8+版本)
brew install python # Mac
choco install python # Windows用Chocolatey
# 2. 安装Selenium库
pip install selenium -i https://pypi.tuna.tsinghua.edu.cn/simple
# 3. 下载浏览器驱动(重点!)
# Chrome驱动地址:https://chromedriver.chromium.org/downloads
# 版本必须与本地浏览器完全一致!
这里有个血泪教训:去年帮客户调试时发现脚本死活不运行,最后发现是Chrome自动更新后版本不匹配。驱动版本必须精确到小数点后两位,比如Chrome 115.0.5790.110对应的驱动必须是115.0.5790.x。
建议把驱动文件放在项目根目录下,然后这样初始化:
python复制from selenium import webdriver
driver = webdriver.Chrome(executable_path="./chromedriver") # 相对路径更便携
3. 从录制到编写:两种脚本开发模式
3.1 懒人必备:Selenium IDE录制
Edge浏览器现在内置了Selenium IDE插件,就像录屏软件一样简单:
- 打开Edge扩展商店搜索"Selenium IDE"
- 点击录制按钮后正常操作网页
- 右键页面元素可添加断言(如验证"支付成功"文本是否存在)
但录制生成的代码就像方便面——能应急但不健康。我见过最离谱的案例是生成了300行包含绝对XPath的脚本,页面改个按钮位置就全废了。
3.2 职业选手:手动编写Python脚本
这个搜索百度的例子藏着几个关键技巧:
python复制from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
driver.get("https://www.baidu.com")
# 更健壮的定位方式(CSS选择器优先于XPath)
search_box = driver.find_element(By.CSS_SELECTOR, "#kw")
search_box.send_keys("selenium")
# 显式等待比sleep更智能
submit_btn = WebDriverWait(driver, 10).until(
lambda x: x.find_element(By.ID, "su")
)
submit_btn.click()
实际项目中我会用Page Object模式把元素定位和业务逻辑分离,比如:
python复制class BaiduPage:
def __init__(self, driver):
self.driver = driver
self.search_input = (By.ID, "kw")
def search(self, keyword):
self.driver.find_element(*self.search_input).send_keys(keyword)
4. 企业级测试框架搭建实战
4.1 用Pytest组织测试用例
直接上我优化过的项目目录结构:
code复制├── config/
│ ├── browser_config.py # 浏览器参数配置
├── pages/ # 页面对象类
│ ├── login_page.py
├── tests/
│ ├── test_login.py # 测试用例
├── conftest.py # Pytest夹具配置
└── requirements.txt
关键配置示例(conftest.py):
python复制import pytest
from selenium import webdriver
@pytest.fixture(scope="module")
def browser():
driver = webdriver.Chrome()
driver.implicitly_wait(5) # 全局隐式等待
yield driver
driver.quit() # 测试结束后自动关闭
4.2 失败自动截图功能
这个装饰器能帮你在用例失败时保存现场:
python复制def screenshot_on_failure(func):
def wrapper(browser, *args, **kwargs):
try:
return func(browser, *args, **kwargs)
except Exception as e:
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
browser.save_screenshot(f"fail_{timestamp}.png")
raise
return wrapper
4.3 跨浏览器测试方案
用Selenium Grid实现一套脚本多浏览器运行:
python复制# browser_config.py
BROWSERS = {
"chrome": {
"command_executor": "http://192.168.1.100:4444/wd/hub",
"options": webdriver.ChromeOptions()
},
"firefox": {
"command_executor": "http://192.168.1.100:4444/wd/hub",
"options": webdriver.FirefoxOptions()
}
}
启动Grid服务端(需要Docker环境):
bash复制docker run -d -p 4444:4444 --shm-size="2g" selenium/hub
docker run -d -p 5900:5900 --shm-size="2g" selenium/node-chrome
5. 性能优化与常见坑点
5.1 元素定位的六个层级
按优先级使用定位策略:
- ID(最快最稳定)
- CSS Selector(推荐.class或[attribute=value])
- XPath(尽量避免绝对路径)
- Name属性
- 链接文本
- 标签名
5.2 等待机制的三重境界
- 硬等待:
time.sleep(5)(最后的选择) - 隐式等待:
driver.implicitly_wait(10)(全局设置) - 显式等待(最佳实践):
python复制from selenium.webdriver.support import expected_conditions as EC
element = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.ID, "submit"))
)
5.3 高频踩坑记录
- 动态ID问题:遇到id="button-1234"这种动态生成的,改用CSS选择
[id^="button-"] - iframe陷阱:操作前必须
driver.switch_to.frame("frame_name") - 文件上传:不要尝试点击上传按钮,直接用
element.send_keys("/path/to/file") - 验证码处理:测试环境可以临时屏蔽或设置万能验证码
最近在金融项目中发现个隐蔽问题:Chrome的自动填充功能会遮挡表单元素,解决方法是在测试时禁用自动填充:
python复制options = webdriver.ChromeOptions()
options.add_experimental_option("prefs", {
"profile.password_manager_enabled": False,
"credentials_enable_service": False
})
建议把常用操作封装成工具函数,比如这个清理浏览器缓存的函数:
python复制def clear_cache(driver):
driver.execute_cdp_cmd("Network.clearBrowserCache", {})
driver.get("chrome://settings/clearBrowserData")
# 模拟点击清除按钮...
