1. 从嵌入式到测试:Python+Selenium 自动化测试转型实战
作为一名从嵌入式开发转型测试的工程师,我深刻理解手工测试的痛点。每天重复执行相同的测试用例,不仅效率低下,还容易因疲劳导致漏测。Python+Selenium 这套组合拳彻底改变了我的测试工作方式,让我从"点点点"的重复劳动中解放出来。
1.1 为什么选择 Python+Selenium?
对于嵌入式背景的工程师来说,Python 的语法简洁易上手,Selenium 则提供了强大的浏览器自动化能力。这套组合特别适合以下场景:
- 需要频繁回归测试的 Web 应用
- 多浏览器兼容性测试
- 复杂业务流程的端到端测试
- 需要生成详细测试报告的项目
提示:Selenium 支持所有主流浏览器,包括 Chrome、Firefox、Edge 等,测试脚本可以跨浏览器运行。
2. 环境搭建与避坑指南
2.1 Python 环境配置
推荐使用 Python 3.8-3.10 版本,这些版本与 Selenium 4.x 兼容性最好。安装时务必勾选"Add Python to PATH"选项,否则后续会遇到各种路径问题。
验证 Python 安装成功:
bash复制python --version
pip --version
2.2 Selenium 安装与版本管理
使用 pip 安装指定版本的 Selenium:
bash复制pip install selenium==4.39.0
建议固定 Selenium 版本,避免自动升级导致兼容性问题。可以通过以下命令查看已安装版本:
bash复制pip show selenium
2.3 浏览器驱动配置
浏览器驱动是 Selenium 控制浏览器的关键组件。以 Chrome 为例:
- 查看 Chrome 浏览器版本:在地址栏输入
chrome://settings/help - 下载对应版本的 ChromeDriver:ChromeDriver 官网
- 将驱动文件放在固定目录(如
/usr/local/bin或C:\drivers)
验证驱动配置:
python复制from selenium import webdriver
driver = webdriver.Chrome()
driver.get("https://www.baidu.com")
driver.quit()
常见问题:如果遇到"chromedriver cannot be opened"错误,可能是权限问题,执行
chmod +x chromedriver赋予可执行权限。
3. 核心元素定位策略
3.1 八种定位方法详解
Selenium 提供了多种元素定位方式,按优先级排序如下:
- ID 定位:最可靠的方式,元素有唯一 ID 时首选
python复制element = driver.find_element(By.ID, "username")
- Name 定位:适用于表单元素
python复制element = driver.find_element(By.NAME, "password")
- XPath 定位:万能定位方式,适合复杂场景
python复制# 绝对路径(不推荐)
element = driver.find_element(By.XPATH, "/html/body/div[1]/form/input")
# 相对路径+属性
element = driver.find_element(By.XPATH, "//input[@id='search']")
# 文本匹配
element = driver.find_element(By.XPATH, "//button[text()='登录']")
- CSS 选择器:性能优于 XPath,语法简洁
python复制element = driver.find_element(By.CSS_SELECTOR, "#submit.btn-primary")
- Class 名称:注意类名可能有空格
python复制element = driver.find_element(By.CLASS_NAME, "form-control")
- 标签名:适合批量操作同类元素
python复制inputs = driver.find_elements(By.TAG_NAME, "input")
- 链接文本:精确匹配链接文字
python复制element = driver.find_element(By.LINK_TEXT, "忘记密码?")
- 部分链接文本:模糊匹配长链接
python复制element = driver.find_element(By.PARTIAL_LINK_TEXT, "忘记")
3.2 定位策略最佳实践
- 优先使用 ID 和 Name:最稳定可靠
- 动态元素使用 XPath/CSS:应对没有固定属性的元素
- 避免绝对路径:页面结构调整容易导致失效
- 添加等待机制:防止元素未加载完成时报错
- 封装定位方法:提高代码复用性和可维护性
4. 自动化测试实战场景
4.1 登录功能测试
python复制def test_login():
driver.get("https://example.com/login")
# 输入用户名密码
driver.find_element(By.ID, "username").send_keys("testuser")
driver.find_element(By.ID, "password").send_keys("password123")
# 勾选记住我
remember_me = driver.find_element(By.ID, "remember")
if not remember_me.is_selected():
remember_me.click()
# 点击登录按钮
driver.find_element(By.XPATH, "//button[text()='登录']").click()
# 验证登录成功
welcome = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "welcome"))
)
assert "欢迎" in welcome.text
4.2 表单提交测试
python复制def test_form_submission():
driver.get("https://example.com/register")
# 填写表单
driver.find_element(By.NAME, "name").send_keys("张三")
driver.find_element(By.NAME, "email").send_keys("zhangsan@example.com")
# 选择下拉框
from selenium.webdriver.support.select import Select
country = Select(driver.find_element(By.ID, "country"))
country.select_by_visible_text("中国")
# 提交表单
driver.find_element(By.CSS_SELECTOR, "button[type='submit']").click()
# 验证提交成功
success = WebDriverWait(driver, 10).until(
EC.visibility_of_element_located((By.CLASS_NAME, "alert-success"))
)
assert "注册成功" in success.text
4.3 文件上传处理
python复制def test_file_upload():
driver.get("https://example.com/upload")
# 文件上传元素
file_input = driver.find_element(By.XPATH, "//input[@type='file']")
# 上传文件(使用绝对路径)
file_path = os.path.abspath("testdata/sample.jpg")
file_input.send_keys(file_path)
# 提交
driver.find_element(By.ID, "upload-btn").click()
# 验证
uploaded = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "uploaded-files"))
)
assert "sample.jpg" in uploaded.text
5. 高级技巧与最佳实践
5.1 等待机制详解
- 隐式等待:全局设置,查找元素时自动等待
python复制driver.implicitly_wait(10) # 单位:秒
- 显式等待:针对特定条件等待
python复制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"))
)
- 常用等待条件:
presence_of_element_located:元素出现在DOM中visibility_of_element_located:元素可见element_to_be_clickable:元素可点击text_to_be_present_in_element:元素包含特定文本
5.2 测试框架集成
将 Selenium 与 unittest 或 pytest 结合,构建完整的测试框架:
python复制import unittest
from selenium import webdriver
class TestLogin(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.driver = webdriver.Chrome()
cls.driver.implicitly_wait(10)
def test_valid_login(self):
self.driver.get("https://example.com/login")
# 测试步骤...
self.assertIn("欢迎", self.driver.title)
@classmethod
def tearDownClass(cls):
cls.driver.quit()
if __name__ == "__main__":
unittest.main()
5.3 Page Object 模式
Page Object 是 Selenium 测试的最佳实践,将页面封装为对象:
python复制class LoginPage:
def __init__(self, driver):
self.driver = driver
self.username = (By.ID, "username")
self.password = (By.ID, "password")
self.submit = (By.XPATH, "//button[text()='登录']")
def enter_credentials(self, username, password):
self.driver.find_element(*self.username).send_keys(username)
self.driver.find_element(*self.password).send_keys(password)
def submit_form(self):
self.driver.find_element(*self.submit).click()
# 使用示例
def test_login():
driver = webdriver.Chrome()
login_page = LoginPage(driver)
login_page.enter_credentials("testuser", "password123")
login_page.submit_form()
assert "欢迎" in driver.title
driver.quit()
6. 常见问题排查
6.1 元素定位失败
可能原因:
- 元素尚未加载完成 → 添加等待
- 元素在 iframe 中 → 切换 iframe
- 元素属性是动态生成的 → 使用模糊匹配
- 页面结构发生变化 → 更新定位方式
解决方案:
python复制# 1. 添加显式等待
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "dynamic-element"))
)
# 2. 处理 iframe
driver.switch_to.frame("iframe-name")
# 3. 动态元素处理
element = driver.find_element(By.XPATH, "//div[contains(@id, 'temp-')]")
6.2 浏览器兼容性问题
解决方案:
- 使用 WebDriverManager 自动管理驱动版本
python复制from webdriver_manager.chrome import ChromeDriverManager
driver = webdriver.Chrome(ChromeDriverManager().install())
- 针对不同浏览器编写兼容代码
python复制if browser == "chrome":
options = webdriver.ChromeOptions()
driver = webdriver.Chrome(options=options)
elif browser == "firefox":
profile = webdriver.FirefoxProfile()
driver = webdriver.Firefox(profile)
6.3 测试稳定性提升技巧
- 使用干净的测试环境:每个测试用例前后清理状态
- 添加失败重试机制:应对偶发性的元素加载失败
- 并行测试:使用 pytest-xdist 加速测试执行
- 日志记录:详细记录测试执行过程
- 屏幕截图:测试失败时自动截图
python复制# 失败重试示例
@pytest.mark.flaky(reruns=3, reruns_delay=2)
def test_flaky():
# 测试代码...
7. 持续集成与部署
将 Selenium 测试集成到 CI/CD 流程中:
7.1 GitHub Actions 配置示例
yaml复制name: Selenium Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.9'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install selenium webdriver-manager
- name: Run tests
run: |
python -m pytest tests/ --html=report.html
- name: Upload report
uses: actions/upload-artifact@v2
with:
name: test-report
path: report.html
7.2 Docker 化测试环境
dockerfile复制FROM python:3.9-slim
# 安装 Chrome
RUN apt-get update && apt-get install -y \
wget \
gnupg \
&& wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
&& echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list \
&& apt-get update && apt-get install -y \
google-chrome-stable \
&& rm -rf /var/lib/apt/lists/*
# 安装驱动管理工具
RUN pip install webdriver-manager
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt
CMD ["pytest", "tests/"]
8. 性能优化技巧
8.1 加速测试执行
- 复用浏览器会话:减少启动/关闭浏览器的开销
- 并行测试:使用 pytest-xdist 并行运行测试
- 无头模式:节省渲染时间
python复制options = webdriver.ChromeOptions()
options.add_argument("--headless")
driver = webdriver.Chrome(options=options)
- 禁用图片加载:减少网络请求
python复制chrome_options = webdriver.ChromeOptions()
prefs = {"profile.managed_default_content_settings.images": 2}
chrome_options.add_experimental_option("prefs", prefs)
8.2 资源管理
- 及时清理资源:确保每个测试完成后释放资源
python复制def tearDown(self):
self.driver.quit()
- 使用上下文管理器:自动管理资源
python复制with webdriver.Chrome() as driver:
# 测试代码...
- 监控资源使用:避免内存泄漏
python复制import psutil
def print_memory_usage():
process = psutil.Process(os.getpid())
print(f"Memory usage: {process.memory_info().rss / 1024 / 1024:.2f} MB")
9. 测试报告与可视化
9.1 生成 HTML 测试报告
使用 pytest-html 插件:
bash复制pip install pytest-html
pytest --html=report.html
9.2 集成 Allure 报告
- 安装 Allure:
bash复制pip install allure-pytest
- 运行测试生成报告:
bash复制pytest --alluredir=./allure-results
allure serve ./allure-results
- 添加详细测试步骤:
python复制import allure
@allure.step("输入用户名")
def enter_username(username):
driver.find_element(By.ID, "username").send_keys(username)
def test_login():
with allure.step("打开登录页面"):
driver.get("https://example.com/login")
enter_username("testuser")
# 更多测试步骤...
10. 移动端测试扩展
10.1 Appium 基础
Appium 是移动端的 Selenium,支持 Android 和 iOS 自动化测试:
python复制from appium import webdriver
desired_caps = {
'platformName': 'Android',
'deviceName': 'emulator-5554',
'app': '/path/to/app.apk'
}
driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)
# 定位元素
element = driver.find_element(By.ID, "com.example:id/button")
element.click()
10.2 跨平台测试策略
- 共用测试逻辑:抽象出与平台无关的测试步骤
- 平台特定适配:针对不同平台实现细节
- 统一报告:合并 Web 和移动端测试结果
python复制class LoginTest:
def __init__(self, driver):
self.driver = driver
def test_login(self, username, password):
# 通用测试逻辑
self.enter_username(username)
self.enter_password(password)
self.click_login()
# 平台特定验证
if isinstance(self.driver, webdriver.Remote):
# 移动端验证
pass
else:
# Web 端验证
pass
11. 测试数据管理
11.1 数据驱动测试
使用 pytest 的 parametrize 实现数据驱动:
python复制import pytest
test_data = [
("admin", "admin123", True),
("test", "wrongpass", False)
]
@pytest.mark.parametrize("username,password,expected", test_data)
def test_login(username, password, expected):
driver.get("https://example.com/login")
driver.find_element(By.ID, "username").send_keys(username)
driver.find_element(By.ID, "password").send_keys(password)
driver.find_element(By.ID, "login-btn").click()
if expected:
assert "欢迎" in driver.title
else:
assert "登录失败" in driver.page_source
11.2 外部数据源
从 JSON 或 CSV 文件读取测试数据:
python复制import json
import csv
# 从 JSON 读取
with open('testdata.json') as f:
test_data = json.load(f)
# 从 CSV 读取
with open('testdata.csv') as f:
reader = csv.DictReader(f)
test_data = [row for row in reader]
12. 测试环境治理
12.1 环境隔离策略
- 使用不同配置文件:区分开发、测试、生产环境
- Docker 容器隔离:每个测试运行在独立容器中
- 数据库快照:测试前恢复干净的数据状态
python复制# 环境配置示例
import configparser
config = configparser.ConfigParser()
config.read('env.ini')
def get_base_url():
return config['TEST']['base_url']
12.2 测试数据清理
确保测试不会留下脏数据:
python复制@pytest.fixture
def clean_up_user():
# 测试前准备
yield
# 测试后清理
delete_test_user("testuser")
def test_user_creation(clean_up_user):
# 测试代码...
13. 安全测试整合
13.1 基础安全测试
- XSS 测试:验证输入过滤
python复制def test_xss_protection():
driver.get("https://example.com/search")
driver.find_element(By.NAME, "query").send_keys("<script>alert(1)</script>")
driver.find_element(By.ID, "search-btn").click()
assert "<script>" not in driver.page_source
- SQL 注入测试:
python复制def test_sql_injection():
driver.get("https://example.com/login")
driver.find_element(By.NAME, "username").send_keys("admin'--")
driver.find_element(By.NAME, "password").send_keys("anything")
driver.find_element(By.ID, "login-btn").click()
assert "登录失败" in driver.page_source
13.2 与 OWASP ZAP 集成
自动化安全扫描:
python复制from zapv2 import ZAPv2
def run_zap_scan(target_url):
zap = ZAPv2(apikey="your-api-key")
# 启动扫描
scan_id = zap.spider.scan(target_url)
while int(zap.spider.status(scan_id)) < 100:
time.sleep(5)
# 获取结果
alerts = zap.core.alerts()
return [alert for alert in alerts if int(alert['risk']) >= 2] # 中高风险
14. 人工智能在测试中的应用
14.1 视觉验证测试
使用 Applitools 进行视觉回归测试:
python复制from applitools.selenium import Eyes
def test_ui_appearance():
eyes = Eyes()
eyes.api_key = 'YOUR_API_KEY'
try:
driver = webdriver.Chrome()
eyes.open(driver, "Test App", "Login Page")
driver.get("https://example.com/login")
eyes.check_window("Login Form")
eyes.close()
finally:
eyes.abort_if_not_closed()
driver.quit()
14.2 自愈式测试
使用机器学习处理元素定位变化:
python复制from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
def smart_find(driver, locator, value, timeout=10):
try:
return WebDriverWait(driver, timeout).until(
EC.presence_of_element_located((locator, value))
)
except:
# 使用AI模型预测新定位方式
new_locator = ai_predict_new_locator(driver, locator, value)
return driver.find_element(*new_locator)
15. 测试左移实践
15.1 契约测试
使用 Pact 进行契约测试:
python复制from pact import Consumer, Provider
def test_user_service_contract():
pact = Consumer('WebFrontend').has_pact_with(Provider('UserService'))
(pact
.given('a user exists')
.upon_receiving('a request for user details')
.with_request('get', '/users/1')
.will_respond_with(200, body={
'id': 1,
'name': 'Test User'
}))
with pact:
# 测试代码验证契约
response = requests.get(pact.uri + '/users/1')
assert response.status_code == 200
assert response.json()['name'] == 'Test User'
15.2 单元测试与集成测试平衡
构建测试金字塔:
- 单元测试:70% 测试覆盖率
- 集成测试:20% 关键路径
- E2E 测试:10% 核心业务流程
python复制# 单元测试示例
def test_calculate_discount():
assert calculate_discount(100, 0.1) == 90
# 集成测试示例
def test_order_flow():
user = create_user()
product = create_product()
order = create_order(user, product)
assert order.status == "created"
# E2E 测试示例
def test_e2e_purchase():
driver.get("https://example.com")
# 完整的购买流程测试...
16. 测试右移实践
16.1 生产环境监控
将自动化测试用例转化为监控检查:
python复制def production_smoke_test():
try:
driver = webdriver.Remote(
command_executor='http://selenium-hub:4444/wd/hub',
options=webdriver.ChromeOptions()
)
driver.get("https://prod.example.com")
assert "Example" in driver.title
# 检查核心功能
driver.find_element(By.LINK_TEXT, "登录").click()
assert "登录" in driver.title
return True
except Exception as e:
logging.error(f"Smoke test failed: {str(e)}")
return False
finally:
driver.quit()
16.2 混沌工程集成
模拟生产环境故障:
python复制from chaoslib import experiment
@experiment
def test_system_resilience():
# 模拟数据库故障
stop_database()
# 验证降级机制
driver.get("https://example.com")
assert "维护中" in driver.page_source
# 恢复
start_database()
assert system_is_healthy()
17. 测试团队协作
17.1 测试用例管理
与 TestRail 集成:
python复制import testrail
def update_test_result(case_id, status, comment=""):
client = testrail.APIClient('https://your.testrail.io/')
client.user = 'user@example.com'
client.password = 'password'
result = client.send_post(
f'add_result_for_case/{run_id}/{case_id}',
{'status_id': status, 'comment': comment}
)
return result
17.2 团队知识共享
构建测试知识库:
- 自动化测试规范
- 元素定位策略指南
- 常见问题解决方案
- 最佳实践案例
python复制def search_knowledge_base(keyword):
# 连接内部知识库API
results = knowledge_base_api.search(keyword)
return format_results(results)
18. 性能测试结合
18.1 Selenium 与 Locust 集成
模拟用户行为进行性能测试:
python复制from locust import HttpUser, task, between
class WebsiteUser(HttpUser):
wait_time = between(5, 15)
@task
def browse_products(self):
self.client.get("/products")
@task
def view_product_detail(self):
with self.client.get("/product/1", catch_response=True) as response:
if "Add to Cart" not in response.text:
response.failure("Product page not loaded correctly")
18.2 性能指标采集
收集页面加载性能数据:
python复制def get_performance_metrics(driver):
metrics = driver.execute_script("""
return window.performance.timing;
""")
return {
'load_time': metrics['loadEventEnd'] - metrics['navigationStart'],
'dom_ready': metrics['domComplete'] - metrics['domLoading']
}
19. 无障碍测试
19.1 无障碍标准验证
使用 axe-core 进行无障碍测试:
python复制def test_accessibility():
driver.get("https://example.com")
# 注入 axe-core 脚本
with open('axe.min.js') as f:
axe_script = f.read()
driver.execute_script(axe_script)
# 运行检查
results = driver.execute_async_script("""
var callback = arguments[arguments.length - 1];
axe.run(document, {}, callback);
""")
violations = results['violations']
assert len(violations) == 0, f"发现 {len(violations)} 个无障碍问题"
19.2 键盘导航测试
验证键盘可操作性:
python复制def test_keyboard_navigation():
driver.get("https://example.com")
# 模拟 Tab 键导航
body = driver.find_element(By.TAG_NAME, 'body')
for _ in range(10):
body.send_keys(Keys.TAB)
active = driver.switch_to.active_element
assert active.get_attribute('tabindex') != '-1', "不可聚焦的元素获得焦点"
20. 国际化测试
20.1 多语言测试
验证界面多语言支持:
python复制@pytest.mark.parametrize("lang", ["en", "zh", "ja"])
def test_language_switch(lang):
driver.get(f"https://example.com?lang={lang}")
# 验证关键元素文本
login_text = {
"en": "Login",
"zh": "登录",
"ja": "ログイン"
}[lang]
assert login_text in driver.find_element(By.ID, "login-btn").text
20.2 RTL 语言支持
测试从右到左语言布局:
python复制def test_rtl_layout():
driver.get("https://example.com?lang=ar")
# 验证 RTL 样式
body = driver.find_element(By.TAG_NAME, 'body')
assert body.value_of_css_property('direction') == 'rtl'
# 验证元素对齐
header = driver.find_element(By.TAG_NAME, 'header')
assert header.value_of_css_property('text-align') == 'right'
21. 测试框架设计模式
21.1 工厂模式创建 Driver
python复制from selenium import webdriver
class DriverFactory:
@staticmethod
def create_driver(browser="chrome"):
if browser == "chrome":
options = webdriver.ChromeOptions()
return webdriver.Chrome(options=options)
elif browser == "firefox":
return webdriver.Firefox()
else:
raise ValueError(f"Unsupported browser: {browser}")
# 使用示例
driver = DriverFactory.create_driver("chrome")
21.2 装饰器记录测试步骤
python复制def log_step(step_name):
def decorator(func):
def wrapper(*args, **kwargs):
print(f"STEP: {step_name}")
return func(*args, **kwargs)
return wrapper
return decorator
class TestLogin:
@log_step("打开登录页面")
def open_login_page(self):
self.driver.get("https://example.com/login")
@log_step("输入用户名")
def enter_username(self, username):
self.driver.find_element(By.ID, "username").send_keys(username)
22. 测试数据工厂
22.1 使用 Factory Boy
python复制import factory
class UserFactory(factory.Factory):
class Meta:
model = dict
username = factory.Faker('user_name')
email = factory.Faker('email')
is_active = True
# 使用示例
test_user = UserFactory()
driver.find_element(By.ID, "username").send_keys(test_user['username'])
22.2 随机测试数据生成
python复制from faker import Faker
def generate_test_data():
fake = Faker()
return {
'name': fake.name(),
'email': fake.email(),
'address': fake.address()
}
# 使用示例
test_data = generate_test_data()
23. 测试覆盖率提升
23.1 代码覆盖率统计
使用 pytest-cov 插件:
bash复制pip install pytest-cov
pytest --cov=myapp tests/
23.2 业务场景覆盖率
构建场景矩阵:
python复制scenarios = [
{"user": "admin", "permission": "all"},
{"user": "editor", "permission": "edit"},
{"user": "viewer", "permission": "read"}
]
@pytest.mark.parametrize("role", scenarios)
def test_role_based_access(role):
# 测试不同角色的访问权限
login(role['user'])
assert get_permissions() == role['permission']
24. 测试代码重构
24.1 消除重复代码
提取公共方法:
python复制class BaseTest:
def login(self, username, password):
self.driver.get("https://example.com/login")
self.driver.find_element(By.ID, "username").send_keys(username)
self.driver.find_element(By.ID, "password").send_keys(password)
self.driver.find_element(By.ID, "login-btn").click()
class TestAdmin(BaseTest):
def test_admin_dashboard(self):
self.login("admin", "admin123")
assert "Admin Dashboard" in self.driver.title
24.2 使用组合模式
构建可复用的测试组件:
python复制class LoginComponent:
def __init__(self, driver):
self.driver = driver
def login(self, username, password):
self.driver.find_element(By.ID, "username").send_keys(username)
self.driver.find_element(By.ID, "password").send_keys(password)
self.driver.find_element(By.ID, "login-btn").click()
class TestCheckout:
def test_guest_checkout(self):
login = LoginComponent(driver)
login.login("guest", "welcome123")
# 继续测试结账流程
25. 测试策略演进
25.1 从手动到自动化的过渡
分阶段实施策略:
- 阶段1:自动化核心业务流程
- 阶段2:自动化高频回归测试
- 阶段3:自动化数据准备和清理
- 阶段4:实现持续测试流水线
25.2 质量门禁设置
在 CI/CD 流程中定义质量标准:
yaml复制# .github/workflows/ci.yml
jobs:
test:
steps:
- run: pytest --cov=myapp
- uses: codecov/codecov-action@v1
quality_gate:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v2
with:
name: coverage
- run: |
coverage=$(cat coverage/coverage.txt | grep TOTAL | awk '{print $4}')
if (( $(echo "$coverage < 80" | bc -l) )); then
echo "覆盖率低于80%: $coverage"
exit 1
fi
26. 新兴技术适配
26.1 Web Components 测试
测试 Shadow DOM 元素:
python复制def test_shadow_dom():
driver.get("https://example.com/web-components")
# 访问 Shadow DOM
host = driver.find_element(By.CSS_SELECTOR, "custom-element")
shadow_root = driver.execute_script("return arguments[0].shadowRoot", host)
# 定位 Shadow DOM 中的元素
button = shadow_root.find_element(By.CSS_SELECTOR, "button")
button.click()
26.2 GraphQL API 测试
测试 GraphQL 接口:
python复制def test_graphql_query():
query = """
query {
user(id: 1) {
name
email
}
}
"""
driver.get("https://example.com/graphql")
driver.execute_script(f"""
document.querySelector('#graphql-query').value = `{query}`;
document.querySelector('#execute-btn').click();
""")
result = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "result"))
)
assert '"name":' in result.text
27. 测试资产治理
27.1 测试代码审查
建立测试代码审查清单:
- 可读性:命名清晰,结构合理
- 可维护性:避免重复,适当抽象
- 可靠性:足够的等待和重试机制
- 独立性:测试用例相互独立
- 有效性:验证业务价值而不仅是实现
27.2 测试代码质量指标
监控测试代码质量:
python复制# pylintrc 示例
[MASTER]
load-plugins=pylint.extensions.mccabe
[METRICS]
max-complexity=10
min-public-methods=1
max-module-lines=1000
28. 测试效能度量
28.1 关键指标跟踪
- 自动化测试覆盖率:代码/业务场景覆盖率
- 测试执行时间:单次运行/每日累计时间
- 缺陷逃逸率:生产环境发现的缺陷比例
- 测试维护成本:维护测试用例的时间占比
- 反馈速度:从代码提交到测试反馈的时间
28.2 持续改进机制
定期回顾优化:
- 测试用例价值分析:识别高/低价值测试
- 失败测试分析:分类处理不稳定测试
- 技术债务管理:规划测试代码重构
- 工具链评估:持续评估新技术/工具
python复制def