☰
Python+Selenium自动化测试实战与优化技巧
2026/10/27 22:53:03 网站建设 项目流程

1. 为什么选择Python+Selenium做自动化测试

十年前我刚入行测试时,手工点击页面按钮到凌晨三点的经历让我至今难忘。现在Python+Selenium的组合已经成为Web自动化测试的事实标准,这背后有几个关键原因:

首先,Python的语法就像说人话一样简单。我带的实习生经常开玩笑说:"这代码读起来像英语小作文"。比如定位元素只需要driver.find_element(By.ID, "username"),比Java的WebDriver driver = new FirefoxDriver();清爽多了。对于测试脚本这种需要频繁修改的场景,Python的动态类型和简洁语法能节省大量时间。

其次,Selenium的跨浏览器支持实在太香。记得2016年某个紧急项目需要兼容IE11,我用Selenium Grid只花了半天就搭建好了测试环境。现在最新版的Selenium 4更是原生支持CDP协议,连Chrome DevTools的功能都能直接调用。

2. 环境搭建避坑指南

2.1 Python安装的玄学问题

新手最容易栽在Python环境上。最近帮同事排查一个诡异问题:同样的脚本在他电脑上报No module named selenium,但pip list明明显示已安装。最终发现他同时安装了Python 3.8和3.9,而PATH指向的是3.8,pip却装到了3.9的site-packages里。

建议用以下命令检查环境一致性:

which python # 查看Python解释器路径 which pip # 查看pip路径 pip list # 查看当前环境安装的包

2.2 Selenium的版本矩阵

Selenium 4有个大坑:它要求浏览器驱动必须严格匹配浏览器版本。上周我用webdriver_manager自动下载驱动时,就遇到了Chrome 115版本找不到对应驱动的尴尬情况。

这是目前验证过的稳定组合:

组件版本备注
Python3.8+3.7已停止维护
Selenium4.10+旧版API不同
ChromeDriver114-116新版可能不兼容
Firefox(geckodriver)最新ESR版企业版更稳定

3. 元素定位的实战技巧

3.1 比XPath更香的CSS选择器

早期我特别依赖XPath,直到遇到一个动态ID的商城页面,XPath路径长得能绕显示器三圈。后来发现CSS选择器才是真神器:

# 找包含"购物车"文字的span driver.find_element(By.CSS_SELECTOR, "span:contains('购物车')") # 找class为price且父元素是div的span driver.find_element(By.CSS_SELECTOR, "div > span.price")

警告::contains()不是标准CSS,仅在Selenium中可用。正式环境建议用text()=xxx的XPath

3.2 等待的艺术

元素加载不同步是最常见的报错原因。我总结出三级等待策略:

  1. 硬等待:time.sleep(3)(最后手段)
  2. 隐式等待:driver.implicitly_wait(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, "dynamicElement")) )

4. 框架设计进阶

4.1 Page Object模式改造

看过太多"面条代码"式的测试脚本,维护起来简直噩梦。这是我团队现在用的PO模式结构:

project/ ├── pages/ │ ├── login_page.py │ └── dashboard_page.py ├── tests/ │ └── test_login.py └── utilities/ ├── config_reader.py └── custom_waits.py

其中login_page.py的典型写法:

class LoginPage: def __init__(self, driver): self.driver = driver self.username_field = (By.ID, "username") self.password_field = (By.XPATH, "//input[@type='password']") def enter_credentials(self, username, password): self.driver.find_element(*self.username_field).send_keys(username) self.driver.find_element(*self.password_field).send_keys(password) def click_login(self): self.driver.find_element(By.CSS_SELECTOR, "button.login-btn").click()

4.2 异常处理模板

这个try-catch模板帮我定位过无数诡异问题:

try: element.click() except Exception as e: screenshot_path = f"screenshots/failure_{datetime.now().strftime('%Y%m%d_%H%M%S')}.png" driver.save_screenshot(screenshot_path) page_source_path = f"page_source/failure_{datetime.now().strftime('%Y%m%d_%H%M%S')}.html" with open(page_source_path, "w", encoding="utf-8") as f: f.write(driver.page_source) raise AssertionError(f"元素点击失败,截图已保存到{screenshot_path}") from e

5. 真实案例:电商下单流程测试

最近用这套方法测试某跨境电商平台,发现三个关键问题:

  1. 货币切换BUG:
# 测试步骤 home_page.select_currency("EUR") product_page.add_to_cart() assert "€" in cart_page.get_total_price() # 这里报错

最终发现是CDN缓存导致货币符号没更新

  1. 地址自动填充失效: 通过分析发现是Google Places API的key过期了

  2. 移动端支付跳转超时: 用driver.context切换到WebView后才成功定位到元素

6. 持续集成实战

在Jenkins中这样配置能节省大量时间:

pipeline { agent any environment { PYTHON_PATH = 'C:\\Python38' CHROME_DRIVER = 'drivers/chromedriver.exe' } stages { stage('Test') { steps { bat ''' set PATH=%PYTHON_PATH%;%PYTHON_PATH%\\Scripts;%PATH% python -m pytest tests/ --alluredir=./allure-results ''' } } } post { always { allure includeProperties: false, jdk: '', results: [[path: 'allure-results']] } } }

7. 性能优化技巧

  1. 复用浏览器会话:
options = webdriver.ChromeOptions() options.add_experimental_option("debuggerAddress", "127.0.0.1:9222") driver = webdriver.Chrome(options=options) # 连接已打开的浏览器
  1. 并行测试方案:
from concurrent.futures import ThreadPoolExecutor def run_test(browser): # 测试代码... with ThreadPoolExecutor(max_workers=3) as executor: executor.map(run_test, ["chrome", "firefox", "edge"])
  1. 智能等待改进:
def wait_for_animation(driver, timeout=30): WebDriverWait(driver, timeout).until( lambda d: d.execute_script("return jQuery.active == 0") )

8. 移动端测试特别处理

Hybrid应用测试需要特别注意这个流程:

  1. 先获取当前上下文
contexts = driver.contexts # ["NATIVE_APP", "WEBVIEW_com.example"]
  1. 切换到WebView
driver.switch_to.context(contexts[1])
  1. 现在可以用常规CSS选择器定位元素了

关键点:必须开启App的WebView调试模式,在代码中需要指定appPackage和appActivity

9. 常见报错解决方案

这是我整理的排错清单:

错误信息可能原因解决方案
NoSuchElementException元素未加载/定位器错误1. 增加等待时间 2. 检查iframe 3. 更新定位器
ElementClickInterceptedException元素被遮挡1. 滚动到元素 2. 使用JavaScript点击
StaleElementReferenceExceptionDOM已更新重新获取元素引用
InvalidSelectorExceptionXPath/CSS语法错误使用浏览器开发者工具验证

10. 最新趋势:Selenium 4的相对定位

Selenium 4新增的相对定位API简直不要太方便:

from selenium.webdriver.support.relative_locator import with_tag_name password_field = driver.find_element(By.ID, "password") submit_button = driver.find_element( with_tag_name("button").below(password_field) )

支持的方向包括:

  • above()
  • below()
  • to_left_of()
  • to_right_of()
  • near()(50像素范围内)

11. 可视化报告生成

用Allure生成这样的报告只需三步:

  1. 安装依赖:
pip install allure-pytest
  1. 添加装饰器:
@allure.title("测试登录功能") @allure.feature("认证模块") def test_login(): ...
  1. 运行测试:
pytest --alluredir=./allure-results allure serve ./allure-results

生成的报告包含自动录制的操作步骤截图和DOM快照

12. 无头模式优化

Chrome无头模式的新参数能提升20%执行速度:

options = webdriver.ChromeOptions() options.add_argument("--headless=new") # 新版无头模式 options.add_argument("--disable-gpu") options.add_argument("--window-size=1920,1080") # 避免响应式布局问题

13. 元素状态检查大全

这些判断方法能避免很多Flaky测试:

def is_clickable(element): return element.is_displayed() and element.is_enabled() def is_disappeared(driver, locator, timeout=5): try: WebDriverWait(driver, timeout).until_not( EC.presence_of_element_located(locator) ) return True except TimeoutException: return False

14. 跨域处理技巧

遇到跨域iframe时可以这样操作:

# 先切换到iframe driver.switch_to.frame("iframe_id") # 操作iframe内的元素 driver.find_element(...).click() # 切回主文档 driver.switch_to.default_content()

注意:如果iframe是动态加载的,需要先等待其加载完成

15. 文件上传终极方案

各种文件上传场景的处理方法:

  1. 普通input上传:
driver.find_element(By.CSS_SELECTOR, "input[type='file']").send_keys("/path/to/file")
  1. Flash/ActiveX控件:考虑用AutoIT或PyWinAuto

  2. 拖拽上传:用ActionChains模拟

file_input = driver.find_element(...) drop_area = driver.find_element(...) actions = ActionChains(driver) actions.drag_and_drop(file_input, drop_area).perform()

16. 验证码处理策略

  1. 测试环境禁用验证码(推荐)
  2. 设置万能验证码如"0000"
  3. 使用OCR服务(准确率约70%)
  4. 人工干预接口(通过API获取验证码)

17. 测试数据管理

我用Faker库生成逼真的测试数据:

from faker import Faker fake = Faker("zh_CN") test_user = { "name": fake.name(), "email": fake.email(), "address": fake.address(), "phone": fake.phone_number() }

18. 性能对比测试

用time模块简单测算操作耗时:

start_time = time.time() driver.find_element(...).click() end_time = time.time() print(f"点击操作耗时:{(end_time - start_time)*1000:.2f}毫秒")

更专业的可以用BrowserMob Proxy做网络性能分析

19. 浏览器日志分析

获取控制台日志排查JS错误:

logs = driver.get_log("browser") for log in logs: if log["level"] == "SEVERE": print(f"[JS错误] {log['message']}")

20. 自动化测试的未来

最近在试验SeleniumBase框架,它内置了很多实用功能:

from seleniumbase import BaseCase class MyTest(BaseCase): def test_example(self): self.open("https://example.com") self.assert_title("Example Domain") self.assert_element("div h1")

这种扩展框架可能会成为新趋势,特别是它自带的自动重试机制和智能等待,能显著降低Flaky测试的出现概率

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

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

立即咨询