Selenium自动化测试全解
·
目录
Selenium 简介
Selenium 是一个功能强大的开源自动化测试框架,主要用于Web应用程序的自动化测试。它通过模拟真实用户行为来测试Web应用的交互性和功能性,支持跨浏览器、跨平台测试,是当前最流行的Web自动化测试工具之一。
主要特点
- 多浏览器支持:包括 Chrome、Firefox、Edge、Safari 等主流浏览器
- 多语言绑定:支持 Python、Java、C#、Ruby、JavaScript 等多种编程语言
- 跨平台:可在 Windows、Linux、macOS 等操作系统上运行
- 丰富的API:提供完整的浏览器控制功能和DOM操作接口
核心组件详解
1. WebDriver
WebDriver 是 Selenium 的核心组件,通过浏览器特定的驱动程序直接与浏览器通信:
- ChromeDriver - 用于 Google Chrome 浏览器
- GeckoDriver - 用于 Mozilla Firefox 浏览器
- EdgeDriver - 用于 Microsoft Edge 浏览器
- SafariDriver - 用于 Apple Safari 浏览器
这些驱动程序作为浏览器和Selenium脚本之间的桥梁,遵循W3C WebDriver标准协议。
2. Selenium IDE
Selenium IDE (Integrated Development Environment) 是一个浏览器扩展,提供:
- 录制回放功能:记录用户操作并生成可执行的测试脚本
- 导出功能:可将测试用例导出为多种编程语言的代码
- 调试工具:支持断点和步骤执行
适用于快速创建简单的测试用例和原型验证。
3. Selenium Grid
Selenium Grid 是一个分布式测试工具,支持:
- 并行测试:在多台机器上同时运行测试
- 跨平台测试:在不同操作系统和浏览器组合上执行测试
- 负载平衡:合理分配测试任务到不同节点
典型应用场景包括:
- 大规模回归测试
- 跨浏览器兼容性测试
- 提高测试执行效率
Python 环境下的详细配置
安装过程
-
安装 Selenium 库:
pip install selenium -
下载对应浏览器的 WebDriver:
- ChromeDriver 下载地址:https://sites.google.com/chromium.org/driver/
- GeckoDriver 下载地址:https://github.com/mozilla/geckodriver/releases
- 确保下载的驱动程序版本与浏览器版本匹配
-
配置方式:
- 环境变量法:将驱动程序所在目录添加到系统PATH环境变量中
- 直接指定路径:在代码中明确指定驱动程序路径
基础配置示例
from selenium import webdriver
# 方法1:使用环境变量配置
driver = webdriver.Chrome() # 自动从PATH查找chromedriver
# 方法2:指定驱动程序路径
driver = webdriver.Chrome(executable_path='/path/to/chromedriver')
# 方法3:使用Service对象(推荐Selenium 4+)
from selenium.webdriver.chrome.service import Service
service = Service('/path/to/chromedriver')
driver = webdriver.Chrome(service=service)
完整操作示例及解析
下面是一个详细的百度搜索自动化测试示例,包含完整的异常处理和等待机制:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
def baidu_search(keyword):
# 初始化浏览器实例
driver = webdriver.Chrome()
try:
# 打开百度首页
driver.get("https://www.baidu.com")
print(f"当前页面标题: {driver.title}")
# 验证是否成功加载百度首页
assert "百度一下" in driver.title
# 定位搜索框元素
search_box = driver.find_element(By.ID, "kw")
# 输入搜索关键词
search_box.clear() # 先清空可能存在的默认内容
search_box.send_keys(keyword)
# 模拟按下回车键
search_box.send_keys(Keys.RETURN)
# 等待搜索结果加载完成
wait = WebDriverWait(driver, 10)
results = wait.until(
EC.presence_of_all_elements_located((By.CSS_SELECTOR, "div.result.c-container"))
)
# 输出前5条搜索结果
print("\n搜索结果前5条:")
for i, result in enumerate(results[:5], 1):
title = result.find_element(By.TAG_NAME, "h3").text
link = result.find_element(By.TAG_NAME, "a").get_attribute("href")
print(f"{i}. {title} ({link})")
# 截图保存搜索结果
driver.save_screenshot("search_results.png")
# 短暂停留以便观察
time.sleep(2)
except Exception as e:
print(f"测试执行失败: {str(e)}")
driver.save_screenshot("error.png")
finally:
# 确保浏览器关闭
driver.quit()
if __name__ == "__main__":
baidu_search("Selenium自动化测试")
元素定位方法详解
Selenium 提供多种元素定位策略,适用于不同场景:
1. ID 定位
element = driver.find_element(By.ID, "username")
适用场景:元素有唯一ID时最快速可靠的定位方式
2. 类名定位
elements = driver.find_elements(By.CLASS_NAME, "btn-primary")
注意:一个元素可能有多个类名,类名通常不唯一
3. CSS 选择器定位
element = driver.find_element(By.CSS_SELECTOR, "div.content > input[name='email']")
优势:
- 语法与前端开发一致
- 定位灵活精准
- 性能优于XPath
4. XPath 定位
element = driver.find_element(By.XPATH, "//div[@class='container']//a[contains(text(),'登录')]")
适用场景:
- 复杂DOM结构
- 需要基于文本内容定位
- 需要向上或向下遍历DOM树
5. 链接文本定位
element = driver.find_element(By.LINK_TEXT, "用户协议")
element = driver.find_element(By.PARTIAL_LINK_TEXT, "协议")
仅适用于<a>标签,精确或模糊匹配链接文本
6. 标签名定位
buttons = driver.find_elements(By.TAG_NAME, "button")
通常用于获取同一类型的多个元素
7. Name属性定位
element = driver.find_element(By.NAME, "password")
适用于表单元素的标准定位方式
最佳实践建议
-
定位策略优先级:
- 优先使用ID
- 其次使用CSS选择器
- 复杂场景使用XPath
- 避免使用非确定性的定位方式(如索引位置)
-
元素定位技巧:
# 组合定位策略 driver.find_element(By.XPATH, "//input[@id='username' and @class='form-control']") # 相对定位 form = driver.find_element(By.ID, "login-form") username = form.find_element(By.NAME, "username") # 等待元素可交互 element = WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.ID, "submit-btn")) ) -
常见问题解决:
- 元素不可见:先滚动到元素位置
driver.execute_script("arguments[0].scrollIntoView();", element) - 元素在iframe中:需要先切换iframe
driver.switch_to.frame("iframe-name") - 动态ID:使用其他稳定属性定位
- 元素不可见:先滚动到元素位置
等待机制深度解析
1. 强制等待(不推荐)
time.sleep(5) # 固定等待5秒
问题:无论元素是否已加载完成都会等待,降低测试效率
2. 隐式等待(全局设置)
driver.implicitly_wait(10) # 全局超时10秒
特点:
- 适用于所有元素查找操作
- 只需设置一次
- 无法处理特定条件的等待
3. 显式等待(推荐)
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "dynamic-element"))
)
常用等待条件:
visibility_of_element_located- 元素可见element_to_be_clickable- 元素可点击text_to_be_present_in_element- 元素包含特定文本invisibility_of_element_located- 元素不可见frame_to_be_available_and_switch_to_it- iframe可用
高级应用场景
1. 文件上传处理
# 标准文件上传控件
upload = driver.find_element(By.ID, "file-upload")
upload.send_keys("/absolute/path/to/file.txt")
# 隐藏的文件输入框(需JavaScript处理)
driver.execute_script("document.getElementById('hidden-file-input').style.display='block';")
hidden_upload = driver.find_element(By.ID, "hidden-file-input")
hidden_upload.send_keys("/path/to/file.pdf")
2. 下拉选择框操作
from selenium.webdriver.support.ui import Select
select = Select(driver.find_element(By.ID, "country"))
# 选择方式
select.select_by_visible_text("中国") # 按显示文本
select.select_by_value("CN") # 按value属性
select.select_by_index(1) # 按选项索引
# 获取所有选项
options = select.options
for option in options:
print(option.text, option.get_attribute("value"))
# 多选下拉框操作
multi_select = Select(driver.find_element(By.NAME, "languages"))
multi_select.deselect_all() # 取消所有选择
multi_select.select_by_value("en")
multi_select.select_by_value("zh")
3. 弹窗处理
# 等待并处理alert
WebDriverWait(driver, 5).until(EC.alert_is_present())
alert = driver.switch_to.alert
print(alert.text) # 获取弹窗文本
alert.accept() # 确认
# alert.dismiss() # 取消
# 带输入的提示框
prompt = driver.switch_to.alert
prompt.send_keys("输入内容")
prompt.accept()
# 模态对话框处理
modal = WebDriverWait(driver, 10).until(
EC.visibility_of_element_located((By.ID, "modal-dialog"))
)
modal.find_element(By.CLASS_NAME, "confirm-btn").click()
4. 浏览器多窗口/标签页管理
# 获取当前窗口句柄
main_window = driver.current_window_handle
# 点击打开新窗口的链接
driver.find_element(By.LINK_TEXT, "新窗口打开").click()
# 切换到新窗口
WebDriverWait(driver, 5).until(lambda d: len(d.window_handles) > 1)
for handle in driver.window_handles:
if handle != main_window:
driver.switch_to.window(handle)
break
# 在新窗口操作
print("新窗口标题:", driver.title)
# 关闭新窗口并切回主窗口
driver.close()
driver.switch_to.window(main_window)
性能优化与最佳实践
-
定位优化:
# 避免在循环中重复查找 # 不推荐 for i in range(5): driver.find_element(By.ID, "btn").click() # 推荐 button = driver.find_element(By.ID, "btn") for i in range(5): button.click() # 使用find_elements批量获取 items = driver.find_elements(By.CLASS_NAME, "list-item") -
等待策略优化:
# 设置合理的全局隐式等待 driver.implicitly_wait(3) # 不要设置过长 # 关键操作使用显式等待 WebDriverWait(driver, 10).until( EC.invisibility_of_element_located((By.ID, "loading")) ) -
浏览器配置优化:
# Chrome选项优化 from selenium.webdriver.chrome.options import Options options = Options() options.add_argument("--headless") # 无头模式 options.add_argument("--disable-gpu") # 禁用GPU加速 options.add_argument("--window-size=1920,1080") # 设置窗口大小 driver = webdriver.Chrome(options=options) -
测试数据管理:
- 使用Page Object模式分离测试逻辑和定位器
- 将测试数据外部化(JSON/YAML/Excel)
- 使用工厂模式创建测试数据
常见问题解决方案
-
元素点击不生效:
# 方案1:使用JavaScript点击 driver.execute_script("arguments[0].click();", element) # 方案2:先滚动到元素可见 driver.execute_script("arguments[0].scrollIntoView(true);", element) element.click() # 方案3:使用Actions类模拟点击 from selenium.webdriver.common.action_chains import ActionChains ActionChains(driver).move_to_element(element).click().perform() -
处理动态元素:
# 使用XPath函数处理动态属性 element = driver.find_element(By.XPATH, "//div[starts-with(@id, 'prefix_')]") # 使用CSS选择器匹配部分属性 element = driver.find_element(By.CSS_SELECTOR, "div[id^='prefix']") # 等待元素属性变化 WebDriverWait(driver, 10).until( lambda d: d.find_element(By.ID, "status").get_attribute("class") == "completed" ) -
绕过同源策略限制:
# 处理跨域iframe driver.switch_to.frame(driver.find_element(By.TAG_NAME, "iframe")) # 操作iframe内容 driver.find_element(By.ID, "iframe-content").click() # 返回主文档 driver.switch_to.default_content()
测试框架集成
与pytest集成示例
import pytest
from selenium import webdriver
@pytest.fixture(scope="module")
def browser():
# 测试前初始化
driver = webdriver.Chrome()
driver.implicitly_wait(5)
yield driver
# 测试后清理
driver.quit()
@pytest.mark.parametrize("search_keyword,expected", [
("Python", "Python"),
("Selenium", "Selenium"),
("自动化测试", "自动化测试")
])
def test_baidu_search(browser, search_keyword, expected):
browser.get("https://www.baidu.com")
browser.find_element(By.ID, "kw").send_keys(search_keyword + Keys.RETURN)
assert expected in browser.title
生成测试报告
使用pytest-html插件生成美观的HTML报告:
pytest --html=report.html
学习资源推荐
-
官方文档:
- 主站: https://www.selenium.dev
- Python绑定文档: https://selenium-python.readthedocs.io
-
进阶学习:
- Selenium Grid配置指南
- Page Object设计模式
- 行为驱动开发(BDD)与Selenium集成
-
社区资源:
- Selenium官方Slack频道
- Stack Overflow上的Selenium标签
- GitHub上的开源测试框架
-
持续集成:
- Jenkins集成Selenium测试
- GitHub Actions自动化测试工作流
- Docker化Selenium测试环境
更多推荐
所有评论(0)