测试框架的结构

预计使用 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

框架工作流程

  1. 测试执行流程

    pytest命令 → pytest.ini配置 → conftest.py初始化 → 加载测试用例 → 数据驱动执行
    
  2. 数据驱动过程

    测试用例 → 调用data_loader → 读取YAML文件 → 参数化注入测试数据 → 执行测试逻辑
    
  3. 组件交互

    测试用例(features)
      ├── 使用测试数据(test_data)
      ├── 调用工具方法(utils)
      └── 依赖fixture(conftest)
    

关键优势

  1. 清晰分层

    • 测试用例 (features)
    • 测试数据 (test_data)
    • 工具方法 (utils)
    • 全局配置 (conftest)
  2. 数据驱动灵活性

    • 使用YAML管理测试数据
    • 支持复杂数据结构
    • 易于非技术人员维护
  3. pytest集成

    • 通过conftest管理fixture生命周期
    • 支持参数化测试
    • 丰富的插件生态系统
  4. 可扩展性

    • 轻松添加新测试模块
    • 支持多种测试类型 (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_ 开头

项目结构示例

project_root/
├── features/           # 测试目录(由 testpaths 指定)
│   ├── test_login.py   # 测试文件
│   └── test_payment.py
├── other_dir/          # 不会被搜索(不在 testpaths 中)
│   └── other_tests.py
└── pytest.ini

完整配置的作用总结

这个 pytest.ini 文件配置了:

  1. 自定义标记系统:用于分类和组织测试用例
  2. 默认命令行选项:自动启用详细模式和 HTML 报告生成
  3. 测试目录指定:告诉 pytest 只在 features 目录中查找测试文件

实际效果

当你在项目根目录运行 pytest 时:

  1. pytest 会在 features 目录中查找所有测试文件
  2. 以详细模式运行这些测试
  3. 生成自包含的 HTML 报告到 reports/report.html
  4. 可以使用 -m 选项按标记过滤测试(如 pytest -m smoke

补充说明

如果需要覆盖这些默认设置,可以在命令行中指定其他选项:

# 覆盖测试目录设置
pytest other_test_dir/

# 覆盖报告设置
pytest --html=custom_report.html

# 禁用详细模式
pytest -q
  • 明确指定了测试位置(features 目录)
  • 提供了测试分类机制(markers)
  • 自动生成易读的测试报告
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值