预计使用 python + pytest/unitest + ymal 和ddt数据驱动去搭建一个测试框架
1、首先基本的存放 测试用例的地方 features
2、因为需要测试用例和数据分离,数据另外存放在另一个文件夹 test_data 。里面是ymal 或者给别的格式文件。
3、测试用例的工具类 utils ,放一些常用的方法操作。
4、既然使用 pytest去管理,那么 需要一个文件去配置pytest 的管理 ,放在conftest.py 和pytest.ini 文件里
项目目录结构
project_root/
│
├── features/ # 测试用例实现 (行为驱动或普通测试用例)
│ ├── __init__.py
│ ├── login_feature.py # 示例:登录功能测试
│ └── payment_feature.py # 示例:支付功能测试
│
├── test_data/ # 测试数据文件 (YAML格式)
│ ├── login_data.yaml # 登录测试数据
│ ├── payment_data.yaml # 支付测试数据
│ └── env_config.yaml # 环境配置数据
│
├── utils/ # 工具类库
│ ├── __init__.py
│ ├── data_loader.py # 数据加载工具
│ ├── api_client.py # API请求工具
│ └── db_helper.py # 数据库操作工具
│
├── conftest.py # pytest全局配置和fixture
├── pytest.ini # pytest配置文件
├── requirements.txt # 依赖库
└── README.md # 项目文档
核心文件详细说明
1. 测试数据文件 (test_data/login_data.yaml
)
# 登录测试数据
test_cases:
- case_id: "TC_LOGIN_001"
description: "有效用户登录"
username: "standard_user"
password: "secret_sauce"
expected: "success"
- case_id: "TC_LOGIN_002"
description: "无效密码登录"
username: "standard_user"
password: "wrong_password"
expected: "failure"
- case_id: "TC_LOGIN_003"
description: "锁定用户登录"
username: "locked_out_user"
password: "secret_sauce"
expected: "locked"
2. 数据加载工具 (utils/data_loader.py
)
import yaml
import os
def load_yaml(file_path):
"""加载YAML文件并返回解析后的数据"""
with open(file_path, 'r', encoding='utf-8') as file:
return yaml.safe_load(file)
def get_test_data(file_name, data_key='test_cases'):
"""
获取测试数据
:param file_name: YAML文件名 (不含路径)
:param data_key: 数据在YAML中的键名
:return: 测试数据列表
"""
data_dir = os.path.join(os.path.dirname(__file__), '../test_data')
file_path = os.path.join(data_dir, file_name)
data = load_yaml(file_path)
return data.get(data_key, [])
3. 测试用例实现 (features/login_feature.py
)
import pytest
from utils.data_loader import get_test_data
# 获取测试数据
test_data = get_test_data('login_data.yaml')
@pytest.mark.login
@pytest.mark.parametrize("test_case", test_data,
ids=[f"{case['case_id']}:{case['description']}" for case in test_data])
def test_user_login(test_case, login_page):
"""
用户登录测试
:param test_case: 测试用例数据
:param login_page: 通过fixture提供的登录页面对象
"""
# 执行登录操作
login_page.enter_username(test_case['username'])
login_page.enter_password(test_case['password'])
login_page.click_login()
# 验证结果
if test_case['expected'] == "success":
assert login_page.is_logged_in(), "登录成功但未检测到成功状态"
elif test_case['expected'] == "failure":
assert login_page.get_error_message() == "用户名或密码不正确", "错误消息不匹配"
elif test_case['expected'] == "locked":
assert login_page.get_error_message() == "该用户已被锁定", "锁定用户错误消息不匹配"
4. 核心配置文件 (conftest.py
)
import pytest
from utils.data_loader import load_yaml
# 加载环境配置
env_config = load_yaml('test_data/env_config.yaml')
@pytest.fixture(scope="session")
def base_url():
"""提供基础URL"""
return env_config['base_url']
@pytest.fixture
def login_page(base_url, browser):
"""提供登录页面对象"""
from pages.login_page import LoginPage # 页面对象模型
page = LoginPage(browser)
page.navigate_to(f"{base_url}/login")
yield page
page.cleanup()
# 浏览器fixture (示例)
@pytest.fixture(scope="function")
def browser():
"""浏览器实例"""
from selenium import webdriver
driver = webdriver.Chrome()
driver.implicitly_wait(10)
yield driver
driver.quit()
# 添加自定义命令行选项
def pytest_addoption(parser):
parser.addoption("--env", action="store", default="staging", help="环境选择: staging|production")
@pytest.fixture(scope="session")
def env(request):
"""获取环境配置"""
return request.config.getoption("--env")
5. pytest配置文件 (pytest.ini
)
[pytest]
markers =
login: login tests
payment: payment tests
smoke: smoke tests
regression: regression tests
addopts = -v --html=reports/report.html --self-contained-html
testpaths = features
框架工作流程
-
测试执行流程:
pytest命令 → pytest.ini配置 → conftest.py初始化 → 加载测试用例 → 数据驱动执行
-
数据驱动过程:
测试用例 → 调用data_loader → 读取YAML文件 → 参数化注入测试数据 → 执行测试逻辑
-
组件交互:
测试用例(features) ├── 使用测试数据(test_data) ├── 调用工具方法(utils) └── 依赖fixture(conftest)
关键优势
-
清晰分层:
- 测试用例 (features)
- 测试数据 (test_data)
- 工具方法 (utils)
- 全局配置 (conftest)
-
数据驱动灵活性:
- 使用YAML管理测试数据
- 支持复杂数据结构
- 易于非技术人员维护
-
pytest集成:
- 通过conftest管理fixture生命周期
- 支持参数化测试
- 丰富的插件生态系统
-
可扩展性:
- 轻松添加新测试模块
- 支持多种测试类型 (API/UI/DB)
- 便于集成CI/CD
执行测试
# 运行所有测试
pytest
# 运行特定标记的测试
pytest -m login
# 指定环境运行
pytest --env=production
# 生成Allure报告
pytest --alluredir=./allure-results
这个架构提供了清晰的分层设计,实现了测试用例与数据的完全分离,同时充分利用了pytest的强大功能。通过conftest.py集中管理全局配置和fixture,确保了框架的一致性和可维护性。
二、解析下pytest.ini这个文件
[pytest]
markers =
login: login tests
payment: payment tests
smoke: smoke tests
regression: regression tests
addopts = -v --html=reports/report.html --self-contained-html
testpaths = features
这个 `pytest.ini` 文件是 pytest 的配置文件,它定义了 pytest 的运行参数和行为。让我们逐部分解释这个配置:
### 1. `[pytest]` 部分
```ini
[pytest]
这是配置文件的起始标记,表示以下内容都是 pytest 的配置选项。
2. markers
部分
markers =
login: login tests
payment: payment tests
smoke: smoke tests
regression: regression tests
这部分定义了自定义标记(markers):
- 作用:创建用于分类和组织测试的标记
- 格式:
标记名: 描述
- 具体含义:
login
: 用于标记所有登录相关的测试用例payment
: 用于标记所有支付相关的测试用例smoke
: 用于标记冒烟测试(核心功能快速验证)regression
: 用于标记回归测试(全面功能验证)
使用示例:
@pytest.mark.login
def test_user_login():
# 登录测试代码
pass
@pytest.mark.smoke
def test_critical_function():
# 冒烟测试代码
pass
命令行使用:
# 只运行登录测试
pytest -m login
# 运行冒烟测试
pytest -m smoke
# 排除支付测试
pytest -m "not payment"
3. addopts
部分
addopts = -v --html=reports/report.html --self-contained-html
这部分定义了默认的命令行选项:
- 作用:每次运行 pytest 时自动添加这些选项
- 具体选项:
-v
:详细模式(verbose),显示更详细的测试结果信息--html=reports/report.html
:生成 HTML 格式的测试报告,保存到reports/report.html
--self-contained-html
:生成自包含的 HTML 报告(将所有 CSS/JS 嵌入到单个文件中)
效果:每次运行 pytest
命令时,相当于运行:
pytest -v --html=reports/report.html --self-contained-html
4. testpaths
部分
testpaths = features
这是最重要的配置之一:
- 作用:指定 pytest 查找测试文件的目录
- 具体含义:
- pytest 会自动在
features
目录及其子目录中查找测试文件 - 测试文件需要符合命名规则:
test_*.py
或*_test.py
- 测试函数/方法需要以
test_
开头
- pytest 会自动在
项目结构示例:
project_root/
├── features/ # 测试目录(由 testpaths 指定)
│ ├── test_login.py # 测试文件
│ └── test_payment.py
├── other_dir/ # 不会被搜索(不在 testpaths 中)
│ └── other_tests.py
└── pytest.ini
完整配置的作用总结
这个 pytest.ini
文件配置了:
- 自定义标记系统:用于分类和组织测试用例
- 默认命令行选项:自动启用详细模式和 HTML 报告生成
- 测试目录指定:告诉 pytest 只在
features
目录中查找测试文件
实际效果
当你在项目根目录运行 pytest
时:
- pytest 会在
features
目录中查找所有测试文件 - 以详细模式运行这些测试
- 生成自包含的 HTML 报告到
reports/report.html
- 可以使用
-m
选项按标记过滤测试(如pytest -m smoke
)
补充说明
如果需要覆盖这些默认设置,可以在命令行中指定其他选项:
# 覆盖测试目录设置
pytest other_test_dir/
# 覆盖报告设置
pytest --html=custom_report.html
# 禁用详细模式
pytest -q
- 明确指定了测试位置(features 目录)
- 提供了测试分类机制(markers)
- 自动生成易读的测试报告