2. 测试环境初始化:虚拟环境搭建、依赖管理、conftest.py全局配置
测试环境初始化是授权测试与参数配置的基石。一个隔离、可复现、配置集中的测试环境,能有效避免依赖冲突、环境漂移和配置泄漏。本节将围绕虚拟环境搭建、依赖锁定、以及 conftest.py 的全局夹具与钩子设计展开,确保后续所有测试用例在一致且可控的上下文中执行。
2.1 虚拟环境搭建与依赖管理
推荐使用 venv(Python 3.3+ 内置)或 conda(当项目涉及 C 扩展依赖时)创建隔离环境。以下以 venv 为例,展示标准初始化流程:
# 创建虚拟环境(项目根目录下执行)
python -m venv .venv
# 激活环境(Linux/macOS)
source .venv/bin/activate
# 激活环境(Windows PowerShell)
.venv\Scripts\Activate.ps1
# 安装核心依赖
pip install pytest pytest-xdist pytest-mock requests pyyaml
# 导出依赖锁定文件
pip freeze > requirements.txt
依赖锁定策略: 使用
pip freeze > requirements.txt 锁定所有子依赖版本。对于生产级项目,建议额外使用 pip-tools 或 poetry 管理 requirements.in 与 requirements.txt 的分离,确保可追溯性。
依赖管理的关键在于区分“测试依赖”与“运行依赖”。下表列出本课程场景库的核心依赖分组:
| 依赖类别 | 包名 | 用途 | 版本建议 |
|---|---|---|---|
| 测试框架 | pytest | 测试发现、执行、断言 | >=7.4 |
| 并行加速 | pytest-xdist | 多 worker 并行执行测试 | >=3.3 |
| Mock 与桩 | pytest-mock | 轻量级 mock 夹具 | >=3.11 |
| HTTP 请求 | requests | 模拟 API 调用与授权请求 | >=2.31 |
| 配置解析 | pyyaml | 读取 YAML 格式的授权策略与参数 | >=6.0 |
| 数据验证 | pydantic | 配置模型与参数校验 | >=2.5 |
2.2 conftest.py 全局配置架构
conftest.py 是 pytest 的全局配置入口,位于测试目录根节点。它负责注册夹具(fixture)、钩子函数(hook)和命令行选项。在授权测试场景中,conftest.py 需要承载以下核心职责:
- 加载全局配置:从 YAML/JSON 文件读取授权端点、密钥、角色映射等敏感参数。
- 初始化测试客户端:创建带授权头的 HTTP 会话,供所有测试用例复用。
- 注册授权夹具:提供
auth_token、admin_session、guest_session等预置上下文。 - 定义命令行选项:允许通过
--env、--auth-mode等参数动态切换测试环境。
安全提醒: 切勿将真实密钥、Token 或密码硬编码在
conftest.py 中。应通过环境变量或加密的配置文件注入,并在 .gitignore 中排除敏感文件。
以下是一个典型的 conftest.py 骨架,展示全局夹具与配置加载:
# conftest.py
import pytest
import yaml
import os
from requests import Session
def pytest_addoption(parser):
"""注册自定义命令行选项"""
parser.addoption(
"--env",
action="store",
default="staging",
help="指定测试环境: staging, production"
)
parser.addoption(
"--auth-mode",
action="store",
default="jwt",
help="授权模式: jwt, oauth2, apikey"
)
@pytest.fixture(scope="session")
def config(request):
"""全局配置加载:根据 --env 参数加载对应 YAML 文件"""
env = request.config.getoption("--env")
config_path = f"config/{env}_config.yaml"
if not os.path.exists(config_path):
raise FileNotFoundError(f"配置文件不存在: {config_path}")
with open(config_path, "r") as f:
return yaml.safe_load(f)
@pytest.fixture(scope="session")
def auth_session(config):
"""预授权 HTTP 会话:自动注入 Authorization 头"""
session = Session()
auth_mode = config["auth"]["mode"]
if auth_mode == "jwt":
token = os.environ.get("TEST_JWT_TOKEN")
if not token:
pytest.skip("环境变量 TEST_JWT_TOKEN 未设置")
session.headers.update({"Authorization": f"Bearer {token}"})
elif auth_mode == "apikey":
api_key = config["auth"]["api_key"]
session.headers.update({"X-API-Key": api_key})
return session
@pytest.fixture
def admin_session(auth_session, config):
"""管理员会话:在基础会话上添加 admin 角色标识"""
auth_session.headers.update({"X-Role": "admin"})
return auth_session
@pytest.fixture
def guest_session(auth_session):
"""访客会话:移除角色标识,模拟未授权用户"""
auth_session.headers.pop("X-Role", None)
return auth_session
作用域陷阱:
scope="session" 的夹具在整个测试会话中只创建一次,适合加载配置和创建连接池。但若测试需要修改会话状态(如切换 Token),应使用 scope="function" 或通过 request.addfinalizer 清理,避免状态污染。
2.3 全局配置与夹具依赖关系
下图展示了 conftest.py 中夹具的依赖层级与数据流向,帮助理解配置如何从命令行参数传递到具体测试用例:
2.4 环境初始化检查清单
在编写任何授权测试用例之前,请对照以下清单确认环境就绪:
- 虚拟环境已激活:终端提示符显示
(.venv)前缀。 - 依赖已安装:执行
pip list | grep pytest确认核心包存在。 - 配置文件就位:
config/staging_config.yaml与config/production_config.yaml已创建且包含auth字段。 - 环境变量已设置:
TEST_JWT_TOKEN或对应密钥已通过.env文件或 CI 变量注入。 - conftest.py 位于根测试目录:pytest 能自动发现并加载全局夹具。
- 首次冒烟测试通过:运行
pytest --env=staging --auth-mode=jwt -k "test_config_loaded"确认配置加载正常。
快速验证: 在
conftest.py 中添加一个 pytest_configure 钩子,打印当前环境与授权模式,确保启动时可见:def pytest_configure(config): print(f"\n[环境初始化] env={config.getoption('env')}, auth_mode={config.getoption('auth_mode')}")
2.5 多环境配置结构示例
为了支持不同测试目标(本地开发、CI、预发布),建议采用以下目录结构:
project_root/
├── .venv/ # 虚拟环境(不提交)
├── config/
│ ├── local_config.yaml # 本地开发:mock 授权服务
│ ├── staging_config.yaml # 预发布:真实授权端点(测试账号)
│ └── production_config.yaml # 生产:只读 Token,仅用于健康检查
├── tests/
│ ├── conftest.py # 全局配置与夹具
│ ├── test_auth/ # 授权测试模块
│ └── test_params/ # 参数配置测试模块
├── requirements.txt # 锁定依赖
└── pytest.ini # 默认 pytest 配置
pytest.ini 可预设默认参数,减少命令行输入:
[pytest]
addopts = -v --tb=short --env=staging --auth-mode=jwt
testpaths = tests
python_files = test_*.py
markers =
auth: 授权相关测试
param: 参数配置测试
smoke: 冒烟测试,快速验证环境