如何在庞大的全量测试集中,精准定位并执行核心链路,而无需重构整个测试生态。
实战方案设计
核心思路:方案一提供物理隔离的目录结构,适合稳定版本快速验证;方案二提供动态优先级过滤,支持按需灵活调度。两者结合,可以覆盖大多数业务场景。
实例结构:
test_project/
├── conftest.py # pytest钩子配置
├── pytest.ini # pytest配置文件
├── requirements.txt # 依赖包
├── test_smoke/ # 方案一:冒烟用例独立目录
│ ├── test_login.py
│ └── test_checkout.py
├── test_full/ # 方案一:全量用例目录
│ ├── test_login.py
│ ├── test_checkout.py
│ ├── test_profile.py
│ └── test_orders.py
├── test_cases/ # 方案二:YAML用例集中管理
│ ├── login.yaml
│ ├── checkout.yaml
│ └── profile.yaml
└── run_tests.py # 方案二:自定义命令行参数处理
核心代码实现
1. pytest.ini(pytest基础配置)
[pytest]
testpaths = .
python_files = test_*.py
python_classes = Test*
python_functions = test_*
addopts = -v –tb=short
markers =
smoke: 冒烟测试标记
blocker: 高优先级阻塞问题
critical: 关键优先级问题
normal: 普通优先级问题
2. conftest.py(pytest钩子与自定义参数)
import pytest
from typing import List, Dict
import yaml
import os
def pytest_addoption(parser):
"""自定义命令行参数"""
parser.addoption("–level", action="store", default=None,
help="指定用例优先级: blocker,critical,normal")
parser.addoption("–cases", action="store", default=None,
help="指定用例目录路径")
parser.addoption("–type", action="store", default=None,
help="指定用例类型: yaml, python")
def pytest_configure(config):
"""动态注册marker"""
config.addinivalue_line("markers", "smoke: 冒烟测试")
config.addinivalue_line("markers", "blocker: 阻塞级别")
config.addinivalue_line("markers", "critical: 关键级别")
config.addinivalue_line("markers", "normal: 普通级别")
def pytest_collection_modifyitems(config, items):
"""动态过滤用例(方案二实现)"""
level = config.getoption("–level")
if not level:
return
levels = level.split(",")
selected_items = []
for item in item:
# 获取用例的所有marker
markers = {mark.name for mark in item.iter_markers()}
# 检查是否匹配指定优先级
if any(lvl in markers for lvl in levels):
selected_items.append(item)
items[:] = selected_items
if selected_items:
config.hook.pytest_deselected(items=items)
3. run_tests.py(方案二的YAML解析器)
import pytest
import yaml
import os
from typing import List, Dict
def case_parser(case_type: str, case_dir: str, level: str = None) -> Dict:
"""
YAML用例解析器(方案二核心逻辑)
Args:
case_type: 用例类型,如 'yaml'
case_dir: 用例目录路径
level: 优先级过滤条件
Returns:
包含过滤后用例信息的字典
"""
case_infos = []
if case_type != "yaml":
return {"case_infos": case_infos}
# 遍历目录获取所有YAML文件
yaml_files = []
for root, _, files in os.walk(case_dir):
for file in files:
if file.endswith(('.yaml', '.yml')):
yaml_files.append(os.path.join(root, file))
# 解析YAML用例
yaml_case_infos = []
for yaml_file in yaml_files:
with open(yaml_file, 'r', encoding='utf-8') as f:
data = yaml.safe_load(f)
if isinstance(data, list):
yaml_case_infos.extend(data)
else:
yaml_case_infos.append(data)
# 根据优先级过滤(方案二关键逻辑)
if level:
levels = level.split(",")
for case_info in yaml_case_infos:
if case_info.get("rank") in levels:
case_infos.append(case_info)
else:
case_infos = yaml_case_infos
return {"case_infos": case_infos}
def pytest_generate_tests(metafunc):
"""动态生成测试用例(YAML用例注入)"""
if "case_info" in metafunc.fixturenames:
case_dir = metafunc.config.getoption("–cases")
case_type = metafunc.config.getoption("–type")
level = metafunc.config.getoption("–level")
if case_dir and case_type:
result = case_parser(case_type, case_dir, level)
metafunc.parametrize("case_info", result["case_infos"])
4. 方案一:目录分离的测试用例
test_smoke/test_login.py
import pytest
@pytest.mark.smoke
def test_login_success():
"""冒烟测试:登录成功"""
print("执行冒烟测试:登录成功")
assert True
@pytest.mark.smoke
def test_login_with_valid_credentials():
"""冒烟测试:有效凭证登录"""
print("执行冒烟测试:有效凭证登录")
assert True
test_smoke/test_checkout.py
import pytest
@pytest.mark.smoke
@pytest.mark.blocker
def test_checkout_basic_flow():
"""冒烟测试:基础购物流程"""
print("执行冒烟测试:基础购物流程")
assert True
test_full/test_login.py(包含更多边界场景)
import pytest
@pytest.mark.smoke
def test_login_success():
"""全量测试:登录成功"""
assert True
@pytest.mark.normal
def test_login_with_invalid_password():
"""全量测试:错误密码登录"""
assert True
@pytest.mark.normal
def test_login_with_empty_fields():
"""全量测试:空字段登录"""
assert True
@pytest.mark.critical
def test_login_with_locked_account():
"""全量测试:锁定账号登录"""
assert True
5. 方案二:YAML用例文件
test_cases/login.yaml
– desc: 登录用例-正常登录
rank: blocker
steps:
– step: 打开登录页面
expected: 页面加载成功
– step: 输入用户名密码
expected: 输入成功
– step: 点击登录按钮
expected: 登录成功跳转
– desc: 登录用例-错误密码
rank: normal
steps:
– step: 打开登录页面
expected: 页面加载成功
– step: 输入用户名和错误密码
expected: 输入成功
– step: 点击登录按钮
expected: 提示密码错误
– desc: 登录用例-锁定账号
rank: critical
steps:
– step: 打开登录页面
expected: 页面加载成功
– step: 输入锁定账号
expected: 输入成功
– step: 点击登录按钮
expected: 提示账号已锁定
test_cases/checkout.yaml
– desc: 购物流程-基础流程
rank: blocker
steps:
– step: 选择商品
expected: 商品选中
– step: 加入购物车
expected: 购物车数量增加
– step: 提交订单
expected: 订单提交成功
– desc: 购物流程-库存不足
rank: critical
steps:
– step: 选择库存不足商品
expected: 商品选中
– step: 加入购物车
expected: 提示库存不足
6. YAML用例驱动测试(方案二执行器)
test_yaml_runner.py
import pytest
def test_yaml_case(case_info):
"""
YAML用例通用执行器
通过conftest.py中的pytest_generate_tests动态注入用例
"""
print(f"\\n执行用例:{case_info['desc']}")
print(f"优先级:{case_info.get('rank', '无')}")
for idx, step in enumerate(case_info['steps'], 1):
print(f"步骤{idx}: {step['step']}")
print(f"预期: {step['expected']}")
# 这里可以添加实际的测试逻辑
# 例如调用API、操作页面等
assert True # 简化示例,实际应根据步骤执行结果断言
7. requirements.txt
pytest>=7.0.0
pyyaml>=6.0
pytest-html>=3.0.0
执行示例与命令
方案一:目录分离模式执行
# 只执行冒烟测试(指定smoke目录)
pytest test_smoke/ -v
# 执行全量测试(指定full目录)
pytest test_full/ -v
# 使用自定义参数执行冒烟测试
pytest –cases=./test_smoke –type=python -v
方案二:优先级过滤模式执行
# 只执行blocker和critical级别用例(冒烟测试)
pytest –level=blocker,critical -v
# 执行指定级别用例
pytest –level=normal -v
# 结合YAML用例执行
pytest test_yaml_runner.py –cases=./test_cases –type=yaml –level=blocker,critical -v
组合场景执行
# 执行冒烟目录 + blocker级别用例
pytest test_smoke/ –level=blocker -v
# 并行执行多个测试集合
pytest test_smoke/ test_full/ –level=blocker,critical -v
实例亮点与最佳实践体现
方案一体现:
- test_smoke/ 和 test_full/ 物理分离,结构清晰
- 通过 pytest 命令直接指定目录执行,简单高效
- 适合项目稳定后,冒烟用例不常变化的场景
方案二体现:
- YAML 用例统一管理,便于维护和版本控制
- 通过 –level 参数动态过滤,支持灵活调度
- 适合用例频繁调整、需要按优先级分批执行的场景
两者结合:
- 目录分离处理核心稳定链路(如登录、支付)
- YAML + 优先级处理需要动态调整的业务场景(如营销活动)
- 通过同一个配置体系(pytest.ini + conftest.py)统一管理
工程化细节:
- pytest 钩子实现动态过滤,无需修改测试代码
- Marker 体系标准化用例分类
- YAML 解析器支持优先级字段过滤,完全复现你提供的逻辑
网硕互联帮助中心





评论前必须登录!
注册